not done yet
This commit is contained in:
parent
b73af5f92f
commit
49c15f6fb6
15 changed files with 473 additions and 389 deletions
5
bad.ang
Normal file
5
bad.ang
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import "lib/list.ang"
|
||||
|
||||
write(str(map([1, 2, 3], func(n: number) number {
|
||||
return n*n
|
||||
})))
|
||||
150
cli/main.go
150
cli/main.go
|
|
@ -6,6 +6,7 @@ import (
|
|||
"log"
|
||||
"neemek.com/anglais/core"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
|
|
@ -24,45 +25,34 @@ type WorkingDirectoryResolver struct {
|
|||
workingDirectory string
|
||||
}
|
||||
|
||||
func (r *WorkingDirectoryResolver) Resolve(path string) (core.Node, error) {
|
||||
func (r *WorkingDirectoryResolver) Resolve(path string) (string, error) {
|
||||
pth := filepath.Join(r.workingDirectory, path)
|
||||
f, err := os.ReadFile(pth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
src := string(f)
|
||||
|
||||
l := core.NewLexer(src)
|
||||
|
||||
tokens, err := l.Tokenize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := core.NewParser(tokens)
|
||||
|
||||
tree, err := p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tree, nil
|
||||
return string(f), nil
|
||||
}
|
||||
|
||||
func (cmd *RunCmd) Run(ctx *Context) error {
|
||||
func (r *WorkingDirectoryResolver) IsSame(a, b string) bool {
|
||||
apath := filepath.Clean(filepath.Join(r.workingDirectory, a))
|
||||
bpath := filepath.Clean(filepath.Join(r.workingDirectory, b))
|
||||
|
||||
return apath == bpath
|
||||
}
|
||||
|
||||
func makeChunk(ctx *Context, filepath string, ignoreWarnings bool) (*core.Chunk, error) {
|
||||
if ctx.Debug {
|
||||
log.Println("Reading file")
|
||||
}
|
||||
|
||||
f, err := os.ReadFile(cmd.File)
|
||||
f, err := os.ReadFile(filepath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var chunk *core.Chunk
|
||||
if !cmd.Bytecode {
|
||||
src := string(f)
|
||||
|
||||
if ctx.Debug {
|
||||
|
|
@ -76,18 +66,18 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
tokens, err := l.Tokenize()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(tokens) <= 1 {
|
||||
log.Fatal("Empty file")
|
||||
return nil, errors.New("empty file")
|
||||
}
|
||||
|
||||
if ctx.Debug {
|
||||
log.Printf("Lexed %d tokens", len(tokens))
|
||||
|
||||
}
|
||||
p := core.NewParser(tokens)
|
||||
p := core.NewParser(src, tokens)
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Initialized parser")
|
||||
|
|
@ -101,7 +91,7 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
|
||||
// if there were parsing errors, print them out
|
||||
if err != nil {
|
||||
print(err.(core.ParsingError).Format([]rune(src)))
|
||||
print(err.(core.ParsingError).Format())
|
||||
log.Fatal("Parsing had errors")
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +104,7 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
log.Println("Setting imports resolver")
|
||||
}
|
||||
|
||||
dir, _ := filepath.Split(cmd.File)
|
||||
dir, _ := path.Split(filepath)
|
||||
c.SetImportsResolver(&WorkingDirectoryResolver{
|
||||
dir,
|
||||
})
|
||||
|
|
@ -124,7 +114,7 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
}
|
||||
err = c.Compile(tree)
|
||||
if err != nil {
|
||||
var e core.CompilerError
|
||||
var e core.FormatedError
|
||||
if errors.As(err, &e) {
|
||||
log.Fatal(e.Format())
|
||||
}
|
||||
|
|
@ -132,15 +122,35 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
}
|
||||
|
||||
// if there were non-critical warnings, report them
|
||||
if !cmd.IgnoreWarnings && len(c.Warnings) != 0 {
|
||||
if !ignoreWarnings && len(c.Warnings) != 0 {
|
||||
for _, warning := range c.Warnings {
|
||||
log.Println(warning.Format())
|
||||
}
|
||||
log.Fatal("compiler reported warning(s) (ignore warnings with the --ignore-warnings option)")
|
||||
}
|
||||
|
||||
chunk = c.Chunk
|
||||
return c.Chunk, nil
|
||||
}
|
||||
|
||||
func (cmd *RunCmd) Run(ctx *Context) error {
|
||||
var chunk *core.Chunk
|
||||
if !cmd.Bytecode {
|
||||
c, err := makeChunk(ctx, cmd.File, cmd.IgnoreWarnings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chunk = c
|
||||
} else {
|
||||
if ctx.Debug {
|
||||
log.Println("Reading file")
|
||||
}
|
||||
|
||||
f, err := os.ReadFile(cmd.File)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Registering GOB types")
|
||||
}
|
||||
|
|
@ -177,85 +187,15 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
|||
type CompileCmd struct {
|
||||
File string `arg:"" name:"file" help:"File to compile program from" type:"existingfile"`
|
||||
Output string `arg:"" name:"output" help:"File path to output bytecode to" type:"path"`
|
||||
IgnoreWarnings bool `name:"ignore-warnings" help:"Ignore warning messages"`
|
||||
}
|
||||
|
||||
func (cmd *CompileCmd) Run(ctx *Context) error {
|
||||
if ctx.Debug {
|
||||
log.Println("Reading file")
|
||||
}
|
||||
|
||||
f, err := os.ReadFile(cmd.File)
|
||||
|
||||
c, err := makeChunk(ctx, cmd.File, cmd.IgnoreWarnings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src := string(f)
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Initializing lexer")
|
||||
}
|
||||
l := core.NewLexer(src)
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Lexing all tokens")
|
||||
}
|
||||
tokens, err := l.Tokenize()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Initializing parser")
|
||||
}
|
||||
p := core.NewParser(tokens)
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Parsing tree")
|
||||
}
|
||||
|
||||
tree, err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err.(*core.ParsingError).Format([]rune(src)))
|
||||
}
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Initialized compiler")
|
||||
}
|
||||
|
||||
c := core.NewCompiler([]rune(src))
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Setting import resolver")
|
||||
}
|
||||
|
||||
dir, _ := filepath.Split(cmd.File)
|
||||
c.SetImportsResolver(&WorkingDirectoryResolver{
|
||||
dir,
|
||||
})
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Compiling parse tree")
|
||||
}
|
||||
|
||||
err = c.Compile(tree)
|
||||
if err != nil {
|
||||
var e core.CompilerError
|
||||
if errors.As(err, &e) {
|
||||
log.Fatal(e.Format())
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// if there were non-critical warnings, report them
|
||||
if len(c.Warnings) != 0 {
|
||||
for _, warning := range c.Warnings {
|
||||
log.Println(warning.Format())
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Registering GOB types")
|
||||
}
|
||||
|
|
@ -266,7 +206,7 @@ func (cmd *CompileCmd) Run(ctx *Context) error {
|
|||
log.Println("Serializing chunk")
|
||||
}
|
||||
|
||||
serialized := c.Chunk.Serialize()
|
||||
serialized := c.Serialize()
|
||||
|
||||
if ctx.Debug {
|
||||
log.Println("Writing file")
|
||||
|
|
|
|||
|
|
@ -69,6 +69,48 @@ func GetAllTestCases() map[string]AllTestCase {
|
|||
},
|
||||
},
|
||||
},
|
||||
"constant_list_concat": {
|
||||
"a := [1, 2] + [3]",
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
"a",
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{1},
|
||||
&NumberValue{2},
|
||||
&NumberValue{3},
|
||||
},
|
||||
},
|
||||
0,
|
||||
},
|
||||
},
|
||||
},
|
||||
"list_concat": {
|
||||
"a := [1, 2]\nb := a + [3]",
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
"a",
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{1},
|
||||
&NumberValue{2},
|
||||
},
|
||||
},
|
||||
0,
|
||||
},
|
||||
&VariableValue{
|
||||
"b",
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{1},
|
||||
&NumberValue{2},
|
||||
&NumberValue{3},
|
||||
},
|
||||
},
|
||||
0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +144,7 @@ func TestAll(t *testing.T) {
|
|||
c := NewCompiler([]rune(tc.src))
|
||||
|
||||
t.Log("Compiling parse tree")
|
||||
err = c.Compile(tree)
|
||||
err = c.compile(tree)
|
||||
if err != nil {
|
||||
t.Fatalf("Compiler had an error: %s", err)
|
||||
}
|
||||
|
|
@ -135,7 +177,7 @@ func BenchmarkAll(b *testing.B) {
|
|||
tree, _ := p.Parse()
|
||||
|
||||
c := NewCompiler([]rune(tc.src))
|
||||
_ = c.Compile(tree)
|
||||
_ = c.compile(tree)
|
||||
|
||||
vm := NewVM(c.Chunk, 256, 256)
|
||||
|
||||
|
|
|
|||
170
core/compiler.go
170
core/compiler.go
|
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -10,7 +11,8 @@ type Compiler struct {
|
|||
ip Pos
|
||||
scope Pos
|
||||
|
||||
imports map[string]Node
|
||||
imports []string
|
||||
importStack *Stack[string]
|
||||
resolver ImportsResolver
|
||||
source []rune
|
||||
Warnings []CompilerError
|
||||
|
|
@ -19,7 +21,8 @@ type Compiler struct {
|
|||
}
|
||||
|
||||
type ImportsResolver interface {
|
||||
Resolve(path string) (Node, error)
|
||||
Resolve(path string) (string, error)
|
||||
IsSame(a, b string) bool
|
||||
}
|
||||
|
||||
type LocalVariable struct {
|
||||
|
|
@ -106,7 +109,8 @@ func NewCompiler(source []rune) *Compiler {
|
|||
NewChunk(make([]Bytecode, 0), make([]Value, 0)),
|
||||
0,
|
||||
0,
|
||||
make(map[string]Node),
|
||||
make([]string, 0),
|
||||
NewStack[string](256),
|
||||
nil,
|
||||
source,
|
||||
[]CompilerError{},
|
||||
|
|
@ -141,7 +145,17 @@ func (c *Compiler) addConstant(value Value) {
|
|||
c.add(Bytecode(len(chunk.Constants) - 1))
|
||||
}
|
||||
|
||||
func (c *Compiler) Compile(tree Node) error {
|
||||
func (c *Compiler) Compile(p *Program) error {
|
||||
for _, i := range p.Imports {
|
||||
if err := c.resolveImport(i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return c.compile(p.Block)
|
||||
}
|
||||
|
||||
func (c *Compiler) compile(tree Node) error {
|
||||
if tree == nil {
|
||||
panic("compile called with nil value")
|
||||
}
|
||||
|
|
@ -172,7 +186,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
c.addConstant(v)
|
||||
} else {
|
||||
for _, n := range l.items {
|
||||
err := c.Compile(n)
|
||||
err := c.compile(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -200,7 +214,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
c.add(InstructionConstant)
|
||||
c.addConstant(v)
|
||||
} else {
|
||||
err := c.Compile(tree.(*UnaryNode).value)
|
||||
err := c.compile(tree.(*UnaryNode).value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -226,7 +240,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
case BlockNodeType:
|
||||
c.addDescend()
|
||||
for _, n := range tree.(*BlockNode).statements {
|
||||
err := c.Compile(n)
|
||||
err := c.compile(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -246,7 +260,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
}
|
||||
|
||||
// the stack should have whether the condition was truthful
|
||||
err = c.Compile(n.condition)
|
||||
err = c.compile(n.condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -259,7 +273,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
c.advance(2)
|
||||
|
||||
// this part would be executed if the value was true
|
||||
err = c.Compile(n.do)
|
||||
err = c.compile(n.do)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -277,7 +291,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
c.putU16(jumpByPos, uint16(c.ip-jumpByPos-2))
|
||||
|
||||
if n.otherwise != nil {
|
||||
err := c.Compile(n.otherwise)
|
||||
err := c.compile(n.otherwise)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -297,7 +311,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
}
|
||||
|
||||
conditionPos := c.ip
|
||||
err = c.Compile(n.condition)
|
||||
err = c.compile(n.condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -306,7 +320,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
jumpValuePos := c.ip
|
||||
c.advance(2)
|
||||
|
||||
err = c.Compile(n.do)
|
||||
err = c.compile(n.do)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -322,13 +336,13 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
|
||||
if n.name == "_" {
|
||||
// allow non-ish statements
|
||||
err := c.Compile(n.value)
|
||||
err := c.compile(n.value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.add(InstructionPop)
|
||||
} else {
|
||||
if c.isVarDeclaredHere(n.name) {
|
||||
if n.declare && c.isVarDeclaredHere(n.name) {
|
||||
return c.error(fmt.Sprintf("%s is already declared in this scope", n.name), n)
|
||||
}
|
||||
|
||||
|
|
@ -370,13 +384,13 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
return c.error(fmt.Sprintf("argument #%d does not have expected type signature: got %s, requires %s", i, sig, f.In[i]), arg)
|
||||
}
|
||||
|
||||
err = c.Compile(arg)
|
||||
err = c.compile(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = c.Compile(n.source)
|
||||
err = c.compile(n.source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -413,6 +427,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
// reset instruction pointer (ip)
|
||||
c.ip = 0
|
||||
|
||||
c.descend()
|
||||
for _, p := range n.parameters {
|
||||
c.registerVar(p.Name, p.Signature)
|
||||
}
|
||||
|
|
@ -421,14 +436,11 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = c.Compile(n.logic)
|
||||
err = c.compile(n.logic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.logic.Type() != BlockNodeType {
|
||||
c.stack.Pop()
|
||||
}
|
||||
c.ascend()
|
||||
|
||||
mc.Constants[fi] = &FunctionValue{
|
||||
n.name,
|
||||
|
|
@ -444,7 +456,7 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
|
||||
case AccessNodeType:
|
||||
n := tree.(*AccessNode)
|
||||
err := c.Compile(n.source)
|
||||
err := c.compile(n.source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -453,20 +465,8 @@ func (c *Compiler) Compile(tree Node) error {
|
|||
n.property,
|
||||
})
|
||||
|
||||
case ImportNodeType:
|
||||
n := tree.(*ImportNode)
|
||||
|
||||
t := c.resolveImport(n.path).(*BlockNode)
|
||||
|
||||
for _, statement := range t.statements {
|
||||
err := c.Compile(statement)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case ReturnNodeType:
|
||||
err := c.Compile(tree.(*ReturnNode).value)
|
||||
err := c.compile(tree.(*ReturnNode).value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -494,11 +494,11 @@ func (c *Compiler) compileBinary(binary *BinaryNode) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
err := c.Compile(binary.Left)
|
||||
err := c.compile(binary.Left)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Compile(binary.Right)
|
||||
err = c.compile(binary.Right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -512,6 +512,8 @@ func (c *Compiler) compileBinary(binary *BinaryNode) error {
|
|||
|
||||
if res.Type() == TypeString {
|
||||
c.add(InstructionStringConcatenation)
|
||||
} else if res.Type() == TypeList {
|
||||
c.add(InstructionConcatLists)
|
||||
} else {
|
||||
c.add(InstructionAdd)
|
||||
}
|
||||
|
|
@ -574,12 +576,16 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
|||
|
||||
if contents == nil {
|
||||
contents = sig
|
||||
} else {
|
||||
} else if !contents.Matches(sig) {
|
||||
contents = &AnySignature{}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if contents == nil {
|
||||
return nil, c.error("can't deduce content type", n)
|
||||
}
|
||||
|
||||
return &ListSignature{
|
||||
contents,
|
||||
}, nil
|
||||
|
|
@ -594,7 +600,7 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if l != r {
|
||||
if !l.Matches(r) {
|
||||
return nil, c.error(fmt.Sprintf("cannot perform binary %s on different types: %s and %s", n.BinaryOperation, l, r), n)
|
||||
}
|
||||
|
||||
|
|
@ -611,6 +617,10 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
|||
return &StringSignature{}, nil
|
||||
case TypeNumber:
|
||||
return &NumberSignature{}, nil
|
||||
case TypeList:
|
||||
return &ListSignature{
|
||||
l.(*ListSignature).Contents,
|
||||
}, nil
|
||||
default:
|
||||
return nil, c.error(fmt.Sprintf("cannot perform binary addition on type %s", l), n)
|
||||
}
|
||||
|
|
@ -774,6 +784,7 @@ func (c *Compiler) affirmReturnSignature(tree Node, sig TypeSignature) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Printf("try affirming %s matches %s", v, sig)
|
||||
if !sig.Matches(v) {
|
||||
return c.error(fmt.Sprintf("function cannot return a value with type %s. defined to be %s", v, sig), n.value)
|
||||
}
|
||||
|
|
@ -857,7 +868,7 @@ func (c *Compiler) getVar(name string) {
|
|||
}
|
||||
|
||||
func (c *Compiler) setVar(name string, value Node, declare bool) error {
|
||||
err := c.Compile(value)
|
||||
err := c.compile(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -915,7 +926,7 @@ func (c *Compiler) isTreeConstant(tree Node) bool {
|
|||
case BinaryNodeType:
|
||||
return c.isTreeConstant(tree.(*BinaryNode).Left) && c.isTreeConstant(tree.(*BinaryNode).Right)
|
||||
case BlockNodeType, ConditionalNodeType, LoopNodeType, AssignNodeType, CallNodeType, FunctionNodeType,
|
||||
ReturnNodeType, AccessNodeType, BreakpointNodeType, ImportNodeType, ReferenceNodeType:
|
||||
ReturnNodeType, AccessNodeType, BreakpointNodeType, ReferenceNodeType:
|
||||
return false
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected node %s", tree))
|
||||
|
|
@ -984,10 +995,42 @@ func (c *Compiler) computeBinary(n *BinaryNode) (Value, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if l.Type() != r.Type() {
|
||||
return nil, c.error(fmt.Sprintf("cannot perform binary %s on different types %s and %s", n.BinaryOperation, l.Type(), r.Type()), n)
|
||||
}
|
||||
|
||||
// perform type check
|
||||
switch n.BinaryOperation {
|
||||
case BinaryAddition:
|
||||
if l.Type() != StringValueType && l.Type() != NumberValueType && l.Type() != ListValueType {
|
||||
return nil, c.error(fmt.Sprintf("cannot add values of type %s", l.Type()), n)
|
||||
}
|
||||
case BinarySubtraction, BinaryMultiplication, BinaryDivision, BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
|
||||
if l.Type() != NumberValueType {
|
||||
return nil, c.error(fmt.Sprintf("cannot do binary %s on non-number type %s", n.BinaryOperation, l.Type()), n)
|
||||
}
|
||||
case BinaryAnd, BinaryOr:
|
||||
if l.Type() != BoolValueType {
|
||||
return nil, c.error(fmt.Sprintf("cannot do binary %s on non-boolean type %s", n.BinaryOperation, l.Type()), n)
|
||||
}
|
||||
case BinaryEquality, BinaryInequality:
|
||||
// can compare all types with themselves
|
||||
default:
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
switch n.BinaryOperation {
|
||||
case BinaryAddition:
|
||||
switch l.Type() {
|
||||
case NumberValueType:
|
||||
v = l.(*NumberValue).Number + r.(*NumberValue).Number
|
||||
case StringValueType:
|
||||
v = l.(*StringValue).Text + r.(*StringValue).Text
|
||||
case ListValueType:
|
||||
v = append(l.(*ListValue).Items, r.(*ListValue).Items...)
|
||||
default:
|
||||
return nil, c.error(fmt.Sprintf("cannot perform binary add on type %s", l.Type()), n)
|
||||
}
|
||||
case BinarySubtraction:
|
||||
v = l.(*NumberValue).Number - r.(*NumberValue).Number
|
||||
case BinaryMultiplication:
|
||||
|
|
@ -1058,20 +1101,47 @@ func (c *Compiler) warn(msg string, causer Node) {
|
|||
c.Warnings = append(c.Warnings, c.error(msg, causer))
|
||||
}
|
||||
|
||||
func (c *Compiler) resolveImport(path string) Node {
|
||||
if chunk, ok := c.imports[path]; ok {
|
||||
return chunk
|
||||
func (c *Compiler) resolveImport(path string) error {
|
||||
// if already imported and available
|
||||
for _, i := range c.imports {
|
||||
if c.resolver.IsSame(path, i) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// find tree
|
||||
tree, err := c.resolver.Resolve(path)
|
||||
src, err := c.resolver.Resolve(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
c.imports[path] = tree
|
||||
l := NewLexer(src)
|
||||
tokens, err := l.Tokenize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tree
|
||||
parser := NewParser(src, tokens)
|
||||
p, err := parser.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldChunk := c.Chunk
|
||||
oldSrc := c.source
|
||||
|
||||
c.Chunk = NewChunk([]Bytecode{}, []Value{})
|
||||
c.source = []rune(src)
|
||||
|
||||
if err := c.Compile(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.imports[path] = c.Chunk
|
||||
|
||||
c.Chunk = oldChunk
|
||||
c.source = oldSrc
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Compiler) SetImportsResolver(resolver ImportsResolver) {
|
||||
|
|
@ -1087,7 +1157,7 @@ func (c *Compiler) addU16(v uint16) {
|
|||
c.add(Bytecode(v & 0xff)) // last 8 bits
|
||||
}
|
||||
|
||||
// putU16 put a unsigned 16-bit value at an arbitrary position.
|
||||
// putU16 put an unsigned 16-bit value at an arbitrary position.
|
||||
// p is the position before the value
|
||||
func (c *Compiler) putU16(p Pos, v uint16) {
|
||||
// save original position
|
||||
|
|
|
|||
|
|
@ -502,7 +502,7 @@ func TestCompile(t *testing.T) {
|
|||
c := NewCompiler([]rune(testCase.tree.String()))
|
||||
|
||||
t.Log("Compiling node tree")
|
||||
err := c.Compile(testCase.tree)
|
||||
err := c.compile(testCase.tree)
|
||||
if err != nil {
|
||||
t.Fatalf("Compiling failed: %v", err)
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ func BenchmarkCompile(b *testing.B) {
|
|||
b.Run(name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := NewCompiler([]rune{})
|
||||
_ = c.Compile(testCase.tree)
|
||||
_ = c.compile(testCase.tree)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -573,7 +573,7 @@ func TestCompiler_CleanStack(t *testing.T) {
|
|||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
c := NewCompiler([]rune(tc.tree.String()))
|
||||
err := c.Compile(tc.tree)
|
||||
err := c.compile(tc.tree)
|
||||
if err != nil {
|
||||
t.Fatalf("Compiling failed: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ const (
|
|||
FunctionNodeType
|
||||
ReturnNodeType
|
||||
AccessNodeType
|
||||
ImportNodeType
|
||||
BreakpointNodeType
|
||||
)
|
||||
|
||||
|
|
@ -70,8 +69,6 @@ func (n NodeType) String() string {
|
|||
return "Access"
|
||||
case BreakpointNodeType:
|
||||
return "Breakpoint"
|
||||
case ImportNodeType:
|
||||
return "Import"
|
||||
case UnaryNodeType:
|
||||
return "Unary"
|
||||
}
|
||||
|
|
@ -405,25 +402,6 @@ func (n BlockNode) Bounds() (Pos, Pos) {
|
|||
return n.start, n.end
|
||||
}
|
||||
|
||||
type ImportNode struct {
|
||||
path string
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
}
|
||||
|
||||
func (n ImportNode) Type() NodeType {
|
||||
return ImportNodeType
|
||||
}
|
||||
|
||||
func (n ImportNode) String() string {
|
||||
return fmt.Sprintf("import %s", n.path)
|
||||
}
|
||||
|
||||
func (n ImportNode) Bounds() (Pos, Pos) {
|
||||
return n.start, n.end
|
||||
}
|
||||
|
||||
// ConditionalNode conditionals (if statements)
|
||||
type ConditionalNode struct {
|
||||
condition Node
|
||||
|
|
|
|||
|
|
@ -8,9 +8,15 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type FormatedError interface {
|
||||
Error() string
|
||||
Format() string
|
||||
}
|
||||
|
||||
type ParsingError struct {
|
||||
Description string
|
||||
Causer *Token
|
||||
Source string
|
||||
}
|
||||
|
||||
func (p ParsingError) Error() string {
|
||||
|
|
@ -18,7 +24,8 @@ func (p ParsingError) Error() string {
|
|||
}
|
||||
|
||||
// Format Print a rich and informative error
|
||||
func (p ParsingError) Format(src []rune) string {
|
||||
func (p ParsingError) Format() string {
|
||||
src := []rune(p.Source)
|
||||
builder := strings.Builder{}
|
||||
|
||||
lineNumber := 1
|
||||
|
|
@ -62,20 +69,44 @@ func (p ParsingError) Format(src []rune) string {
|
|||
}
|
||||
|
||||
type Parser struct {
|
||||
source string
|
||||
tokens []Token
|
||||
prev *Token
|
||||
curr *Token
|
||||
pos Pos
|
||||
}
|
||||
|
||||
func NewParser(tokens []Token) *Parser {
|
||||
func NewParser(source string, tokens []Token) *Parser {
|
||||
return &Parser{
|
||||
source: source,
|
||||
tokens: tokens,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) Parse() (Node, error) {
|
||||
type Program struct {
|
||||
Imports []string
|
||||
Block *BlockNode
|
||||
}
|
||||
|
||||
func (p *Program) String() string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
builder.WriteString("=== Imports ===\n")
|
||||
for _, i := range p.Imports {
|
||||
builder.WriteString(i)
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
builder.WriteString("===============\n")
|
||||
|
||||
builder.WriteString(p.Block.String())
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (p *Parser) Parse() (*Program, error) {
|
||||
imports := make([]string, 0)
|
||||
|
||||
// top level statements
|
||||
statements := make([]Node, 0)
|
||||
|
||||
|
|
@ -83,6 +114,14 @@ func (p *Parser) Parse() (Node, error) {
|
|||
p.advance()
|
||||
|
||||
for int(p.pos) < len(p.tokens) && p.curr.Type != TokenEOF {
|
||||
if p.accept(TokenImport) {
|
||||
if err := p.expect(TokenString); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imports = append(imports, p.prev.Lexeme[1:len(p.prev.Lexeme)-1])
|
||||
}
|
||||
|
||||
b, err := p.block(true)
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -92,8 +131,13 @@ func (p *Parser) Parse() (Node, error) {
|
|||
statements = append(statements, b)
|
||||
}
|
||||
|
||||
return &BlockNode{
|
||||
statements: statements,
|
||||
return &Program{
|
||||
imports,
|
||||
&BlockNode{
|
||||
statements,
|
||||
0,
|
||||
p.curr.Start + p.curr.Length,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +185,7 @@ func (p *Parser) error(error string, causer *Token) error {
|
|||
return ParsingError{
|
||||
Description: error,
|
||||
Causer: causer,
|
||||
Source: p.source,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -643,22 +688,6 @@ func (p *Parser) statement() (Node, error) {
|
|||
return p.condition()
|
||||
}
|
||||
|
||||
case TokenImport:
|
||||
p.advance()
|
||||
start := p.prev.Start
|
||||
|
||||
if err := p.expect(TokenString); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := p.prev.Lexeme[1 : len(p.prev.Lexeme)-1]
|
||||
|
||||
return &ImportNode{
|
||||
path,
|
||||
start,
|
||||
p.prev.Start + p.prev.Length,
|
||||
}, nil
|
||||
|
||||
case TokenFunc:
|
||||
p.advance()
|
||||
|
||||
|
|
@ -867,13 +896,19 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
|||
var s TypeSignature
|
||||
|
||||
if p.accept(TokenFunc) {
|
||||
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||
if err := p.expect(TokenOpenParenthesis); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var in []TypeSignature
|
||||
|
||||
for !p.accept(TokenCloseParenthesis) && (len(in) == 0 || p.accept(TokenComma)) {
|
||||
for !p.accept(TokenCloseParenthesis) {
|
||||
if len(in) > 0 {
|
||||
if err := p.expect(TokenComma); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
sig, err := p.parseSignature()
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -883,10 +918,6 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
|||
in = append(in, sig)
|
||||
}
|
||||
|
||||
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := p.parseSignature()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -896,8 +927,7 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
|||
in,
|
||||
out,
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if err := p.expect(TokenName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -930,6 +960,10 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
|||
|
||||
case "any":
|
||||
s = &AnySignature{}
|
||||
|
||||
default:
|
||||
return nil, p.error("unsupported type: "+name, p.prev)
|
||||
}
|
||||
}
|
||||
|
||||
if p.accept(TokenPipe) {
|
||||
|
|
@ -943,9 +977,5 @@ func (p *Parser) parseSignature() (TypeSignature, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
return nil, p.error("unsupported type: "+name, p.prev)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,15 +68,6 @@ func GoToValue(gov interface{}) Value {
|
|||
return &StringValue{
|
||||
v,
|
||||
}
|
||||
case []interface{}:
|
||||
values := make([]Value, len(v))
|
||||
for i, value := range v {
|
||||
values[i] = GoToValue(value)
|
||||
}
|
||||
|
||||
return &ListValue{
|
||||
values,
|
||||
}
|
||||
case map[string]interface{}:
|
||||
values := map[string]Value{}
|
||||
for key, value := range v {
|
||||
|
|
@ -86,9 +77,17 @@ func GoToValue(gov interface{}) Value {
|
|||
return &ObjectValue{
|
||||
values,
|
||||
}
|
||||
case Value:
|
||||
return v
|
||||
default:
|
||||
if reflect.TypeOf(v).Kind() == reflect.Slice {
|
||||
return &ListValue{
|
||||
v.([]Value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("unsupported automatic type conversion: %v (%s)", gov, reflect.TypeOf(gov).Name()))
|
||||
panic(fmt.Sprintf("unsupported automatic type conversion: %v (%s)", gov, reflect.TypeOf(gov)))
|
||||
}
|
||||
|
||||
type Value interface {
|
||||
|
|
@ -319,24 +318,26 @@ var StringPrototype = map[string]*BuiltinFunctionValue{
|
|||
"split",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&StringSignature{}},
|
||||
&NilSignature{},
|
||||
&ListSignature{
|
||||
&StringSignature{},
|
||||
},
|
||||
},
|
||||
func(vm *VM, this Value, v []Value) (Value, error) {
|
||||
str := this.(*StringValue).String()
|
||||
sep := v[0].(*StringValue).String()
|
||||
|
||||
var out []string
|
||||
var out []Value
|
||||
tmp := strings.Builder{}
|
||||
for i := 0; i < len(str)-len(sep); i++ {
|
||||
tmp.WriteRune([]rune(str)[i])
|
||||
|
||||
if str[i:i+len(sep)] == sep {
|
||||
out = append(out, tmp.String())
|
||||
out = append(out, &StringValue{tmp.String()})
|
||||
tmp.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
return GoToValue(out), nil
|
||||
return &ListValue{out}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
|
|
@ -460,47 +461,6 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
|||
nil,
|
||||
false,
|
||||
},
|
||||
"map": {
|
||||
"map",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{
|
||||
&AnySignature{},
|
||||
},
|
||||
&AnySignature{},
|
||||
},
|
||||
},
|
||||
&ListSignature{},
|
||||
},
|
||||
func(vm *VM, value Value, m []Value) (Value, error) {
|
||||
list := value.(*ListValue)
|
||||
|
||||
v := m[0]
|
||||
var f Value
|
||||
switch a := v.(type) {
|
||||
case *FunctionValue, *BuiltinFunctionValue:
|
||||
f = a
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("not a function to apply: %s", v))
|
||||
}
|
||||
|
||||
for i, item := range list.Items {
|
||||
var err error
|
||||
list.Items[i], err = vm.Call(f, []Value{
|
||||
item,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
"reduce": {
|
||||
"reduce",
|
||||
&FunctionSignature{
|
||||
|
|
|
|||
27
core/vm.go
27
core/vm.go
|
|
@ -102,6 +102,8 @@ const (
|
|||
// items to include minus one. (value of 0 => 1 item, value of 1 => 2 items, etc.) The order is reversed compared
|
||||
// to on the stack; the top value on the stack is the last in the list.
|
||||
InstructionFormList
|
||||
// InstructionConcatLists concatenate lists, producing a new list with the values of both lists. Pops two lists.
|
||||
InstructionConcatLists
|
||||
|
||||
// InstructionBreakpoint for debugging purposes
|
||||
InstructionBreakpoint
|
||||
|
|
@ -187,6 +189,8 @@ func (b Bytecode) String() string {
|
|||
return "APPEND"
|
||||
case InstructionAccessProperty:
|
||||
return "ACCESS_PROPERTY"
|
||||
case InstructionConcatLists:
|
||||
return "CONCAT_LISTS"
|
||||
}
|
||||
return "UNDEFINED"
|
||||
}
|
||||
|
|
@ -377,6 +381,21 @@ var DefaultGlobals = map[string]Value{
|
|||
nil,
|
||||
true,
|
||||
},
|
||||
"byte": &BuiltinFunctionValue{
|
||||
"char",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&StringSignature{}},
|
||||
&NumberSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
s := args[0].(*StringValue).Text
|
||||
b := []byte(s)[0]
|
||||
|
||||
return &NumberValue{float64(b)}, nil
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
"assertEq": &BuiltinFunctionValue{
|
||||
"assertEq",
|
||||
&FunctionSignature{
|
||||
|
|
@ -710,6 +729,14 @@ func (vm *VM) Next() bool {
|
|||
list.Items = append(list.Items, value)
|
||||
vm.stack.Push(list)
|
||||
|
||||
case InstructionConcatLists:
|
||||
r := vm.stack.Pop().(*ListValue)
|
||||
l := vm.stack.Pop().(*ListValue)
|
||||
|
||||
vm.stack.Push(&ListValue{
|
||||
append(l.Items, r.Items...),
|
||||
})
|
||||
|
||||
case InstructionDescend:
|
||||
vm.descend()
|
||||
|
||||
|
|
|
|||
|
|
@ -560,6 +560,37 @@ func GetExecutionTestData() map[string]struct {
|
|||
&NumberValue{5},
|
||||
},
|
||||
},
|
||||
"list_concat": {
|
||||
NewChunk(
|
||||
[]Bytecode{
|
||||
InstructionConstant, 0,
|
||||
InstructionConstant, 1,
|
||||
InstructionConcatLists,
|
||||
},
|
||||
[]Value{
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{1},
|
||||
&NumberValue{2},
|
||||
},
|
||||
},
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{3},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
[]Value{
|
||||
&ListValue{
|
||||
[]Value{
|
||||
&NumberValue{1},
|
||||
&NumberValue{2},
|
||||
&NumberValue{3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
12
lib/list.ang
Normal file
12
lib/list.ang
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
func map(list: list[any], f: func(any)any) list[any] {
|
||||
out := []
|
||||
|
||||
i := 0
|
||||
while i < list.length() {
|
||||
out.append(f(list.at(i)))
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/zsh
|
||||
#!/bin/bash
|
||||
|
||||
echo '=== Building CLI ==='
|
||||
cd cli || exit 1
|
||||
|
|
|
|||
|
|
@ -22,3 +22,6 @@ while x <= 100 {
|
|||
|
||||
x = x + 1
|
||||
}
|
||||
|
||||
assertEq([1, 2] + [3], [1, 2, 3])
|
||||
assertEq(["Eny", "meanie"] + ["minie", "moe"], ["Eny", "meanie", "minie", "moe"])
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ while n < fibonacci_numbers.length() {
|
|||
n = n + 1
|
||||
}
|
||||
|
||||
# return to start of line
|
||||
print(format("%[%D", [char(0x1B), n]))
|
||||
# return to start of line (with carriage return \r)
|
||||
print(char(0x0D))
|
||||
|
||||
x := 0
|
||||
while x < fibonacci_numbers.length() {
|
||||
|
|
|
|||
34
wasm/wasm.go
34
wasm/wasm.go
|
|
@ -13,32 +13,18 @@ type JsResolver struct {
|
|||
jsResolver js.Value
|
||||
}
|
||||
|
||||
func (r *JsResolver) Resolve(name string) (core.Node, error) {
|
||||
func (r *JsResolver) Resolve(name string) (string, error) {
|
||||
jsv := r.jsResolver.Invoke(name)
|
||||
|
||||
if jsv.Type() == js.TypeUndefined {
|
||||
return nil, errors.New("cannot find import with name " + name)
|
||||
return "", errors.New("cannot find import with name " + name)
|
||||
}
|
||||
|
||||
if jsv.Type() != js.TypeString {
|
||||
return nil, errors.New("invalid value for source: " + jsv.String())
|
||||
return "", errors.New("invalid value for source: " + jsv.String())
|
||||
}
|
||||
|
||||
source := jsv.String()
|
||||
|
||||
l := core.NewLexer(source)
|
||||
tokens, err := l.Tokenize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := core.NewParser(tokens)
|
||||
tree, err := p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tree, nil
|
||||
return jsv.String(), nil
|
||||
}
|
||||
|
||||
func jsError(err error) interface{} {
|
||||
|
|
@ -68,14 +54,14 @@ func run(_ js.Value, args []js.Value) interface{} {
|
|||
|
||||
log.Printf("got tokens: %v", tokens)
|
||||
|
||||
parser := core.NewParser(tokens)
|
||||
parser := core.NewParser(source, tokens)
|
||||
|
||||
tree, err := parser.Parse()
|
||||
|
||||
if err != nil {
|
||||
var e core.ParsingError
|
||||
var e core.FormatedError
|
||||
if errors.As(err, &e) {
|
||||
errorHandler.Invoke(e.Format([]rune(source)))
|
||||
errorHandler.Invoke(e.Format())
|
||||
return nil
|
||||
}
|
||||
errorHandler.Invoke(err.Error())
|
||||
|
|
@ -86,7 +72,7 @@ func run(_ js.Value, args []js.Value) interface{} {
|
|||
|
||||
compiler := core.NewCompiler([]rune(source))
|
||||
|
||||
log.Printf("Set imports resolver", tree.String())
|
||||
log.Println("Set imports resolver")
|
||||
|
||||
compiler.SetImportsResolver(&JsResolver{
|
||||
resolver,
|
||||
|
|
@ -118,8 +104,8 @@ func run(_ js.Value, args []js.Value) interface{} {
|
|||
vm.SetGlobal("write", &core.BuiltinFunctionValue{
|
||||
Name: "write",
|
||||
Signature: &core.FunctionSignature{
|
||||
[]core.TypeSignature{&core.StringSignature{}},
|
||||
&core.NilSignature{},
|
||||
In: []core.TypeSignature{&core.StringSignature{}},
|
||||
Out: &core.NilSignature{},
|
||||
},
|
||||
F: func(vm *core.VM, this core.Value, args []core.Value) (core.Value, error) {
|
||||
s := args[0].String()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue