diff --git a/pkg/builtin.go b/pkg/builtin/default_function.go similarity index 99% rename from pkg/builtin.go rename to pkg/builtin/default_function.go index 66251db..37a7f38 100644 --- a/pkg/builtin.go +++ b/pkg/builtin/default_function.go @@ -1,4 +1,4 @@ -package pkg +package builtin type DefaultFunction uint8 diff --git a/pkg/machine.go b/pkg/machine.go deleted file mode 100644 index 60f32a6..0000000 --- a/pkg/machine.go +++ /dev/null @@ -1,285 +0,0 @@ -package pkg - -import ( - "errors" -) - -type MachineState interface { - isDone() bool -} - -type MachineContext interface{} - -type Value interface{} - -type Return struct { - ctx MachineContext - value Value -} - -func (r Return) isDone() bool { - return false -} - -type Env []Value - -type Compute struct { - ctx MachineContext - env Env - term Term[NamedDeBruijn] -} - -func (c Compute) isDone() bool { - return false -} - -type Done struct { - term Term[NamedDeBruijn] -} - -func (d Done) isDone() bool { - return true -} - -type FrameAwaitArg struct { - value Value - ctx MachineContext -} - -type FrameAwaitFunTerm struct { - env Env - term Term[NamedDeBruijn] - ctx MachineContext -} - -type FrameAwaitFunValue struct { - value Value - ctx MachineContext -} - -type FrameForce struct{ ctx MachineContext } - -type FrameConstr struct { - env Env - tag uint64 - fields []Term[NamedDeBruijn] - resolvedFields []Value - ctx MachineContext -} - -type FrameCases struct { - env Env - branches []Term[NamedDeBruijn] - ctx MachineContext -} - -type NoFrame struct{} - -type ExBudget struct { - mem int64 - cpu int64 -} - -func (ex *ExBudget) occurrences(n uint32) { - ex.mem *= int64(n) - ex.cpu *= int64(n) -} - -var DefaultExBudget = ExBudget{ - mem: 14000000, - cpu: 10000000000, -} - -type MachineCosts struct { - startup ExBudget - variable ExBudget - constant ExBudget - lambda ExBudget - delay ExBudget - force ExBudget - apply ExBudget - constr ExBudget - ccase ExBudget - /// Just the cost of evaluating a Builtin node not the builtin itself. - builtin ExBudget -} - -func (mc MachineCosts) get(kind StepKind) ExBudget { - switch kind { - case ExConstant: - return mc.constant - case ExVar: - return mc.variable - case ExLambda: - return mc.lambda - case ExDelay: - return mc.delay - case ExForce: - return mc.force - case ExApply: - return mc.apply - case ExBuiltin: - return mc.builtin - case ExConstr: - return mc.constr - case ExCase: - return mc.ccase - default: - panic("invalid step kind") - } -} - -var DefaultMachineCosts = MachineCosts{ - startup: ExBudget{mem: 100, cpu: 100}, - variable: ExBudget{ - mem: 100, - cpu: 23000, - }, - constant: ExBudget{ - mem: 100, - cpu: 23000, - }, - lambda: ExBudget{ - mem: 100, - cpu: 23000, - }, - delay: ExBudget{ - mem: 100, - cpu: 23000, - }, - force: ExBudget{ - mem: 100, - cpu: 23000, - }, - apply: ExBudget{ - mem: 100, - cpu: 23000, - }, - builtin: ExBudget{ - mem: 100, - cpu: 23000, - }, - // Placeholder values - constr: ExBudget{ - mem: 30000000000, - cpu: 30000000000, - }, - ccase: ExBudget{ - mem: 30000000000, - cpu: 30000000000, - }, -} - -type StepKind uint8 - -const ( - ExConstant StepKind = iota - ExVar - ExLambda - ExApply - ExDelay - ExForce - ExBuiltin - ExConstr - ExCase -) - -type CostModel struct { - machineCosts MachineCosts - // builtinCosts map[Builtin]ExBudget -} - -var DefaultCostModel = CostModel{ - machineCosts: DefaultMachineCosts, -} - -type Machine struct { - costs CostModel - slippage uint32 - exBudget ExBudget - unbudgetedSteps [10]uint32 - Logs []string -} - -func CreateMachine(slippage uint32) Machine { - return Machine{ - DefaultCostModel, - slippage, - DefaultExBudget, - [10]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - make([]string, 0), - } -} - -func (m *Machine) Run(term *Term[NamedDeBruijn]) (Term[NamedDeBruijn], error) { - startupBudget := m.costs.machineCosts.startup - if err := m.spendBudget(startupBudget); err != nil { - return nil, err - } - - var state MachineState = Compute{ctx: NoFrame{}, env: make([]Value, 0), term: term} - - var err error - for { - switch v := state.(type) { - case Compute: - state, err = m.compute() - case Return: - state, err = m.returnCompute() - case Done: - return v.term, nil - } - - if err != nil { - return nil, err - } - } -} - -func (m *Machine) compute() (MachineState, error) { - return nil, nil -} - -func (m *Machine) returnCompute() (MachineState, error) { - return nil, nil -} - -func (m *Machine) forceEvaluate() {} - -func (m *Machine) applyEvaluate() {} - -func (m *Machine) evalBuiltinApp() {} - -func (m *Machine) lookupVar() {} - -func (m *Machine) stepAndMaybeSpend() {} - -func (m *Machine) spendUnbudgetedSteps() error { - for i := range m.unbudgetedSteps { - unspent_step_budget := - m.costs.machineCosts.get(StepKind(i)) - - unspent_step_budget.occurrences(m.unbudgetedSteps[i]) - - if err := m.spendBudget(unspent_step_budget); err != nil { - return err - } - - m.unbudgetedSteps[i] = 0 - } - - m.unbudgetedSteps[9] = 0 - - return nil -} - -func (m *Machine) spendBudget(exBudget ExBudget) error { - m.exBudget.mem -= exBudget.mem - m.exBudget.cpu -= exBudget.cpu - - if m.exBudget.mem < 0 || m.exBudget.cpu < 0 { - return errors.New("out of budget") - } - - return nil -} diff --git a/pkg/machine/cek.go b/pkg/machine/cek.go new file mode 100644 index 0000000..59ed695 --- /dev/null +++ b/pkg/machine/cek.go @@ -0,0 +1,129 @@ +package machine + +import ( + "errors" + + "github.com/blinklabs-io/plutigo/pkg/syn" +) + +type Machine struct { + costs CostModel + slippage uint32 + exBudget ExBudget + unbudgetedSteps [10]uint32 + Logs []string +} + +func NewMachine(slippage uint32) Machine { + return Machine{ + costs: DefaultCostModel, + slippage: slippage, + exBudget: DefaultExBudget, + Logs: make([]string, 0), + + unbudgetedSteps: [10]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + } +} + +func (m *Machine) Run(term *syn.Term[syn.NamedDeBruijn]) (syn.Term[syn.NamedDeBruijn], error) { + startupBudget := m.costs.machineCosts.startup + if err := m.spendBudget(startupBudget); err != nil { + return nil, err + } + + var state MachineState = Compute{ctx: NoFrame{}, env: make([]Value, 0), term: term} + var err error + + for { + switch v := state.(type) { + case Compute: + state, err = m.compute(v.ctx, v.env, v.term) + case Return: + state, err = m.returnCompute() + case Done: + return v.term, nil + } + + if err != nil { + return nil, err + } + } +} + +func (m *Machine) compute( + context MachineContext, + env Env, + term syn.Term[syn.NamedDeBruijn], +) (MachineState, error) { + var state MachineState + + switch t := term.(type) { + case syn.Var[syn.NamedDeBruijn]: + m.stepAndMaybeSpend(ExVar) + + value, exists := env.lookup(uint(t.Name.Index)) + + if !exists { + return nil, errors.New("open term evaluated") + } + + state = Return{ctx: context, value: value} + } + + return state, nil +} + +func (m *Machine) returnCompute() (MachineState, error) { + return nil, nil +} + +func (m *Machine) forceEvaluate() {} + +func (m *Machine) applyEvaluate() {} + +func (m *Machine) evalBuiltinApp() {} + +func (m *Machine) lookupVar() {} + +func (m *Machine) stepAndMaybeSpend(step StepKind) error { + m.unbudgetedSteps[step] += 1 + m.unbudgetedSteps[9] += 1 + + if m.unbudgetedSteps[9] >= m.slippage { + if err := m.spendUnbudgetedSteps(); err != nil { + return err + } + } + + return nil +} + +func (m *Machine) spendUnbudgetedSteps() error { + for i := range m.unbudgetedSteps { + unspent_step_budget := + m.costs.machineCosts.get(StepKind(i)) + + unspent_step_budget.occurrences(m.unbudgetedSteps[i]) + + if err := m.spendBudget(unspent_step_budget); err != nil { + return err + } + + m.unbudgetedSteps[i] = 0 + } + + m.unbudgetedSteps[9] = 0 + + return nil +} + +func (m *Machine) spendBudget(exBudget ExBudget) error { + m.exBudget.mem -= exBudget.mem + m.exBudget.cpu -= exBudget.cpu + + if m.exBudget.mem < 0 || m.exBudget.cpu < 0 { + return errors.New("out of budget") + } + + return nil +} diff --git a/pkg/machine/context.go b/pkg/machine/context.go new file mode 100644 index 0000000..a46817d --- /dev/null +++ b/pkg/machine/context.go @@ -0,0 +1,39 @@ +package machine + +import "github.com/blinklabs-io/plutigo/pkg/syn" + +type MachineContext interface{} + +type FrameAwaitArg struct { + value Value + ctx MachineContext +} + +type FrameAwaitFunTerm struct { + env Env + term syn.Term[syn.NamedDeBruijn] + ctx MachineContext +} + +type FrameAwaitFunValue struct { + value Value + ctx MachineContext +} + +type FrameForce struct{ ctx MachineContext } + +type FrameConstr struct { + env Env + tag uint64 + fields []syn.Term[syn.NamedDeBruijn] + resolvedFields []Value + ctx MachineContext +} + +type FrameCases struct { + env Env + branches []syn.Term[syn.NamedDeBruijn] + ctx MachineContext +} + +type NoFrame struct{} diff --git a/pkg/machine/cost_model.go b/pkg/machine/cost_model.go new file mode 100644 index 0000000..eb9dbe1 --- /dev/null +++ b/pkg/machine/cost_model.go @@ -0,0 +1,104 @@ +package machine + +type MachineCosts struct { + startup ExBudget + variable ExBudget + constant ExBudget + lambda ExBudget + delay ExBudget + force ExBudget + apply ExBudget + constr ExBudget + ccase ExBudget + /// Just the cost of evaluating a Builtin node not the builtin itself. + builtin ExBudget +} + +func (mc MachineCosts) get(kind StepKind) ExBudget { + switch kind { + case ExConstant: + return mc.constant + case ExVar: + return mc.variable + case ExLambda: + return mc.lambda + case ExDelay: + return mc.delay + case ExForce: + return mc.force + case ExApply: + return mc.apply + case ExBuiltin: + return mc.builtin + case ExConstr: + return mc.constr + case ExCase: + return mc.ccase + default: + panic("invalid step kind") + } +} + +var DefaultMachineCosts = MachineCosts{ + startup: ExBudget{mem: 100, cpu: 100}, + variable: ExBudget{ + mem: 100, + cpu: 23000, + }, + constant: ExBudget{ + mem: 100, + cpu: 23000, + }, + lambda: ExBudget{ + mem: 100, + cpu: 23000, + }, + delay: ExBudget{ + mem: 100, + cpu: 23000, + }, + force: ExBudget{ + mem: 100, + cpu: 23000, + }, + apply: ExBudget{ + mem: 100, + cpu: 23000, + }, + builtin: ExBudget{ + mem: 100, + cpu: 23000, + }, + // Placeholder values + constr: ExBudget{ + mem: 30000000000, + cpu: 30000000000, + }, + ccase: ExBudget{ + mem: 30000000000, + cpu: 30000000000, + }, +} + +type StepKind uint8 + +const ( + ExConstant StepKind = iota + ExVar + ExLambda + ExApply + ExDelay + ExForce + ExBuiltin + ExConstr + ExCase +) + +type CostModel struct { + machineCosts MachineCosts + // builtinCosts map[Builtin]ExBudget +} + +var DefaultCostModel = CostModel{ + machineCosts: DefaultMachineCosts, +} diff --git a/pkg/machine/env.go b/pkg/machine/env.go new file mode 100644 index 0000000..275cdda --- /dev/null +++ b/pkg/machine/env.go @@ -0,0 +1,13 @@ +package machine + +type Env []Value + +func (e *Env) lookup(name uint) (*Value, bool) { + idx := len(*e) - int(name) + + if idx < 0 || idx >= len(*e) { + return nil, false + } + + return &(*e)[idx], true +} diff --git a/pkg/machine/ex_budget.go b/pkg/machine/ex_budget.go new file mode 100644 index 0000000..ecb21fa --- /dev/null +++ b/pkg/machine/ex_budget.go @@ -0,0 +1,16 @@ +package machine + +type ExBudget struct { + mem int64 + cpu int64 +} + +func (ex *ExBudget) occurrences(n uint32) { + ex.mem *= int64(n) + ex.cpu *= int64(n) +} + +var DefaultExBudget = ExBudget{ + mem: 14000000, + cpu: 10000000000, +} diff --git a/pkg/machine/state.go b/pkg/machine/state.go new file mode 100644 index 0000000..90acfb7 --- /dev/null +++ b/pkg/machine/state.go @@ -0,0 +1,34 @@ +package machine + +import "github.com/blinklabs-io/plutigo/pkg/syn" + +type MachineState interface { + isDone() bool +} + +type Return struct { + ctx MachineContext + value Value +} + +func (r Return) isDone() bool { + return false +} + +type Compute struct { + ctx MachineContext + env Env + term syn.Term[syn.NamedDeBruijn] +} + +func (c Compute) isDone() bool { + return false +} + +type Done struct { + term syn.Term[syn.NamedDeBruijn] +} + +func (d Done) isDone() bool { + return true +} diff --git a/pkg/machine/value.go b/pkg/machine/value.go new file mode 100644 index 0000000..59d8133 --- /dev/null +++ b/pkg/machine/value.go @@ -0,0 +1,3 @@ +package machine + +type Value interface{} diff --git a/pkg/term.go b/pkg/syn/ast.go similarity index 92% rename from pkg/term.go rename to pkg/syn/ast.go index ad3de7f..7ab6f37 100644 --- a/pkg/term.go +++ b/pkg/syn/ast.go @@ -1,6 +1,10 @@ -package pkg +package syn -import "errors" +import ( + "errors" + + "github.com/blinklabs-io/plutigo/pkg/builtin" +) type Term[T Binder] interface{} @@ -68,7 +72,7 @@ type Apply[T Binder] struct { // (builtin addInteger) type Builtin struct { - DefaultFunction + builtin.DefaultFunction } // (constr 0 (con integer 1) (con string "1234")) diff --git a/pkg/constant.go b/pkg/syn/constant.go similarity index 95% rename from pkg/constant.go rename to pkg/syn/constant.go index 5226514..fcd0ee0 100644 --- a/pkg/constant.go +++ b/pkg/syn/constant.go @@ -1,4 +1,4 @@ -package pkg +package syn import ( "math/big" diff --git a/pkg/program.go b/pkg/syn/program.go similarity index 85% rename from pkg/program.go rename to pkg/syn/program.go index 2b72048..43289ef 100644 --- a/pkg/program.go +++ b/pkg/syn/program.go @@ -1,4 +1,4 @@ -package pkg +package syn type Program[T Binder] struct { version [3]uint32 diff --git a/pkg/typ.go b/pkg/syn/typ.go similarity index 95% rename from pkg/typ.go rename to pkg/syn/typ.go index 9378a76..7573ddb 100644 --- a/pkg/typ.go +++ b/pkg/syn/typ.go @@ -1,4 +1,4 @@ -package pkg +package syn type Typ interface{}