Skip to content

Commit f7daedf

Browse files
committed
extract compile lowering from script call runtime
1 parent 1a0f9ac commit f7daedf

3 files changed

Lines changed: 96 additions & 90 deletions

File tree

docs/architecture.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Key files:
8484
- `vibes/parser_precedence.go` (precedence table + assignable-expression helpers)
8585
- `vibes/parser_types.go` (type-expression parsing)
8686
- `vibes/ast.go`
87+
- `vibes/execution_compile.go` (AST lowering into compiled script functions/classes)
8788

8889
## Modules (`require`)
8990

vibes/execution_compile.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package vibes
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
func (e *Engine) Compile(source string) (*Script, error) {
9+
p := newParser(source)
10+
program, parseErrors := p.ParseProgram()
11+
if len(parseErrors) > 0 {
12+
return nil, combineErrors(parseErrors)
13+
}
14+
15+
functions := make(map[string]*ScriptFunction)
16+
classes := make(map[string]*ClassDef)
17+
18+
for _, stmt := range program.Statements {
19+
switch s := stmt.(type) {
20+
case *FunctionStmt:
21+
if _, exists := functions[s.Name]; exists {
22+
return nil, fmt.Errorf("duplicate function %s", s.Name)
23+
}
24+
functions[s.Name] = &ScriptFunction{Name: s.Name, Params: s.Params, ReturnTy: s.ReturnTy, Body: s.Body, Pos: s.Pos(), Exported: s.Exported, Private: s.Private}
25+
case *ClassStmt:
26+
if _, exists := classes[s.Name]; exists {
27+
return nil, fmt.Errorf("duplicate class %s", s.Name)
28+
}
29+
classDef := &ClassDef{
30+
Name: s.Name,
31+
Methods: make(map[string]*ScriptFunction),
32+
ClassMethods: make(map[string]*ScriptFunction),
33+
ClassVars: make(map[string]Value),
34+
Body: s.Body,
35+
}
36+
for _, prop := range s.Properties {
37+
for _, name := range prop.Names {
38+
if prop.Kind == "property" || prop.Kind == "getter" {
39+
getter := &ScriptFunction{
40+
Name: name,
41+
Body: []Statement{&ReturnStmt{Value: &IvarExpr{Name: name, position: prop.position}, position: prop.position}},
42+
Pos: prop.position,
43+
}
44+
classDef.Methods[name] = getter
45+
}
46+
if prop.Kind == "property" || prop.Kind == "setter" {
47+
setter := &ScriptFunction{
48+
Name: name + "=",
49+
Params: []Param{{
50+
Name: "value",
51+
}},
52+
Body: []Statement{
53+
&AssignStmt{
54+
Target: &IvarExpr{Name: name, position: prop.position},
55+
Value: &Identifier{Name: "value", position: prop.position},
56+
position: prop.position,
57+
},
58+
&ReturnStmt{Value: &Identifier{Name: "value", position: prop.position}, position: prop.position},
59+
},
60+
Pos: prop.position,
61+
}
62+
classDef.Methods[name+"="] = setter
63+
}
64+
}
65+
}
66+
for _, fn := range s.Methods {
67+
classDef.Methods[fn.Name] = &ScriptFunction{Name: fn.Name, Params: fn.Params, ReturnTy: fn.ReturnTy, Body: fn.Body, Pos: fn.Pos(), Private: fn.Private}
68+
}
69+
for _, fn := range s.ClassMethods {
70+
classDef.ClassMethods[fn.Name] = &ScriptFunction{Name: fn.Name, Params: fn.Params, ReturnTy: fn.ReturnTy, Body: fn.Body, Pos: fn.Pos(), Private: fn.Private}
71+
}
72+
classes[s.Name] = classDef
73+
default:
74+
return nil, fmt.Errorf("unsupported top-level statement %T", stmt)
75+
}
76+
}
77+
78+
script := &Script{engine: e, functions: functions, classes: classes, source: source}
79+
script.bindFunctionOwnership()
80+
return script, nil
81+
}
82+
83+
func combineErrors(errs []error) error {
84+
if len(errs) == 1 {
85+
return errs[0]
86+
}
87+
msg := ""
88+
for _, err := range errs {
89+
if msg != "" {
90+
msg += "\n\n"
91+
}
92+
msg += err.Error()
93+
}
94+
return errors.New(msg)
95+
}

vibes/execution_script.go

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,100 +2,10 @@ package vibes
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"strings"
87
)
98

10-
func (e *Engine) Compile(source string) (*Script, error) {
11-
p := newParser(source)
12-
program, parseErrors := p.ParseProgram()
13-
if len(parseErrors) > 0 {
14-
return nil, combineErrors(parseErrors)
15-
}
16-
17-
functions := make(map[string]*ScriptFunction)
18-
classes := make(map[string]*ClassDef)
19-
20-
for _, stmt := range program.Statements {
21-
switch s := stmt.(type) {
22-
case *FunctionStmt:
23-
if _, exists := functions[s.Name]; exists {
24-
return nil, fmt.Errorf("duplicate function %s", s.Name)
25-
}
26-
functions[s.Name] = &ScriptFunction{Name: s.Name, Params: s.Params, ReturnTy: s.ReturnTy, Body: s.Body, Pos: s.Pos(), Exported: s.Exported, Private: s.Private}
27-
case *ClassStmt:
28-
if _, exists := classes[s.Name]; exists {
29-
return nil, fmt.Errorf("duplicate class %s", s.Name)
30-
}
31-
classDef := &ClassDef{
32-
Name: s.Name,
33-
Methods: make(map[string]*ScriptFunction),
34-
ClassMethods: make(map[string]*ScriptFunction),
35-
ClassVars: make(map[string]Value),
36-
Body: s.Body,
37-
}
38-
for _, prop := range s.Properties {
39-
for _, name := range prop.Names {
40-
if prop.Kind == "property" || prop.Kind == "getter" {
41-
getter := &ScriptFunction{
42-
Name: name,
43-
Body: []Statement{&ReturnStmt{Value: &IvarExpr{Name: name, position: prop.position}, position: prop.position}},
44-
Pos: prop.position,
45-
}
46-
classDef.Methods[name] = getter
47-
}
48-
if prop.Kind == "property" || prop.Kind == "setter" {
49-
setter := &ScriptFunction{
50-
Name: name + "=",
51-
Params: []Param{{
52-
Name: "value",
53-
}},
54-
Body: []Statement{
55-
&AssignStmt{
56-
Target: &IvarExpr{Name: name, position: prop.position},
57-
Value: &Identifier{Name: "value", position: prop.position},
58-
position: prop.position,
59-
},
60-
&ReturnStmt{Value: &Identifier{Name: "value", position: prop.position}, position: prop.position},
61-
},
62-
Pos: prop.position,
63-
}
64-
classDef.Methods[name+"="] = setter
65-
}
66-
}
67-
}
68-
for _, fn := range s.Methods {
69-
classDef.Methods[fn.Name] = &ScriptFunction{Name: fn.Name, Params: fn.Params, ReturnTy: fn.ReturnTy, Body: fn.Body, Pos: fn.Pos(), Private: fn.Private}
70-
}
71-
for _, fn := range s.ClassMethods {
72-
classDef.ClassMethods[fn.Name] = &ScriptFunction{Name: fn.Name, Params: fn.Params, ReturnTy: fn.ReturnTy, Body: fn.Body, Pos: fn.Pos(), Private: fn.Private}
73-
}
74-
classes[s.Name] = classDef
75-
default:
76-
return nil, fmt.Errorf("unsupported top-level statement %T", stmt)
77-
}
78-
}
79-
80-
script := &Script{engine: e, functions: functions, classes: classes, source: source}
81-
script.bindFunctionOwnership()
82-
return script, nil
83-
}
84-
85-
func combineErrors(errs []error) error {
86-
if len(errs) == 1 {
87-
return errs[0]
88-
}
89-
msg := ""
90-
for _, err := range errs {
91-
if msg != "" {
92-
msg += "\n\n"
93-
}
94-
msg += err.Error()
95-
}
96-
return errors.New(msg)
97-
}
98-
999
func (s *Script) Call(ctx context.Context, name string, args []Value, opts CallOptions) (Value, error) {
10010
if ctx == nil {
10111
ctx = context.Background()

0 commit comments

Comments
 (0)