From 4679f884a5fbd0a32dcef996dd197a539f73e592 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Mon, 11 Nov 2013 21:26:44 -0500 Subject: [PATCH] support array literal, closes #36 --- bytecode/build.go | 2 +- bytecode/instr.go | 51 +++++++++++++++++--------------- compiler/emitter/emitter.go | 19 ++++++++++-- compiler/parser/grammar.go | 59 +++++++++++++++++++++---------------- runtime/funcvm.go | 13 ++++++-- testdata/src/82-array.agora | 6 ++++ 6 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 testdata/src/82-array.agora diff --git a/bytecode/build.go b/bytecode/build.go index fc45568..90297e5 100644 --- a/bytecode/build.go +++ b/bytecode/build.go @@ -1,4 +1,4 @@ package bytecode const ( - AGORA_BUILD = "8405c1e" + AGORA_BUILD = "dabf335" ) diff --git a/bytecode/instr.go b/bytecode/instr.go index 91a7fb2..9041513 100644 --- a/bytecode/instr.go +++ b/bytecode/instr.go @@ -21,40 +21,43 @@ const ( FLG_Jb // Jump back over n instructions FLG_Sn // Dump n frames FLG_Fn // Set n fields + FLG_Fn2 // Set n field pairs FLG_INVL Flag = 0xFF // Invalid flag ) var ( // The lookup table of Flag values to literal flag names FlagNames = [...]string{ - FLG__: "_", - FLG_K: "K", - FLG_V: "V", - FLG_F: "F", - FLG_A: "A", - FLG_N: "N", - FLG_T: "T", - FLG_An: "An", - FLG_Jf: "Jf", - FLG_Jb: "Jb", - FLG_Sn: "Sn", - FLG_Fn: "Fn", + FLG__: "_", + FLG_K: "K", + FLG_V: "V", + FLG_F: "F", + FLG_A: "A", + FLG_N: "N", + FLG_T: "T", + FLG_An: "An", + FLG_Jf: "Jf", + FLG_Jb: "Jb", + FLG_Sn: "Sn", + FLG_Fn: "Fn", + FLG_Fn2: "Fn2", } // The lookup table of literal flag names to Flag values FlagLookup = map[string]Flag{ - "_": FLG__, - "K": FLG_K, - "V": FLG_V, - "F": FLG_F, - "A": FLG_A, - "N": FLG_N, - "T": FLG_T, - "An": FLG_An, - "Jf": FLG_Jf, - "Jb": FLG_Jb, - "Sn": FLG_Sn, - "Fn": FLG_Fn, + "_": FLG__, + "K": FLG_K, + "V": FLG_V, + "F": FLG_F, + "A": FLG_A, + "N": FLG_N, + "T": FLG_T, + "An": FLG_An, + "Jf": FLG_Jf, + "Jb": FLG_Jb, + "Sn": FLG_Sn, + "Fn": FLG_Fn, + "Fn2": FLG_Fn2, } ) diff --git a/compiler/emitter/emitter.go b/compiler/emitter/emitter.go index 4c925f7..37f5912 100644 --- a/compiler/emitter/emitter.go +++ b/compiler/emitter/emitter.go @@ -182,7 +182,20 @@ func (e *Emitter) emitSymbol(f *bytecode.File, fn *bytecode.Fn, sym *parser.Symb case "args": e.assert(asg == atFalse, errors.New("invalid assignment to the `args` keyword")) e.addInstr(fn, bytecode.OP_PUSH, bytecode.FLG_A, 0) - case ".", "[": + case "[": + if sym.Ar == parser.ArLiteral { + // Array literal + ln := 0 + if !e.isEmpty(sym.First) { + syms := sym.First.([]*parser.Symbol) + ln = len(syms) + e.emitBlock(f, fn, syms) + } + e.addInstr(fn, bytecode.OP_NEW, bytecode.FLG_Fn, uint64(ln)) + break + } + fallthrough + case ".": e.assert(sym.Ar == parser.ArBinary, errors.New("expected `"+sym.Id+"` to have binary arity")) e.emitSymbol(f, fn, sym.Second.(*parser.Symbol), atFalse) e.emitSymbol(f, fn, sym.First.(*parser.Symbol), atFalse) @@ -283,7 +296,7 @@ func (e *Emitter) emitSymbol(f *bytecode.File, fn *bytecode.Fn, sym *parser.Symb // Call e.addInstr(fn, op, bytecode.FLG_An, uint64(len(parms))) case "{": - e.assert(sym.Ar == parser.ArUnary, errors.New("expected `{` to have unary arity")) + e.assert(sym.Ar == parser.ArLiteral, errors.New("expected `{` to have literal arity")) ln := 0 if !e.isEmpty(sym.First) { e.emitAny(f, fn, sym, sym.First) @@ -291,7 +304,7 @@ func (e *Emitter) emitSymbol(f *bytecode.File, fn *bytecode.Fn, sym *parser.Symb ln = len(ar) } } - e.addInstr(fn, bytecode.OP_NEW, bytecode.FLG__, uint64(ln)) + e.addInstr(fn, bytecode.OP_NEW, bytecode.FLG_Fn2, uint64(ln)) case "?": // Similar to if, but yields a value e.assert(sym.Ar == parser.ArTernary, errors.New("expected `?` to have ternary arity")) diff --git a/compiler/parser/grammar.go b/compiler/parser/grammar.go index 1c89bbb..1acddd7 100644 --- a/compiler/parser/grammar.go +++ b/compiler/parser/grammar.go @@ -55,6 +55,20 @@ func (p *Parser) defineGrammar() { p.advance("]") return sym }) + p.prefix("[", func(sym *Symbol) *Symbol { + var ar []*Symbol + for p.tkn.Id != "]" && p.tkn.Id != ";" { + ar = append(ar, p.expression(0)) + if p.tkn.Id != "," { + break + } + p.advance(",") + } + p.advance("]") + sym.First = ar + sym.Ar = ArLiteral + return sym + }) // The logical operators p.infixr("&&", 30, nil) @@ -248,14 +262,12 @@ func (p *Parser) defineGrammar() { // The function/method call parser p.infix("(", 80, func(sym, left *Symbol) *Symbol { var a []*Symbol - if p.tkn.Id != ")" { - for { - a = append(a, p.expression(0)) - if p.tkn.Id != "," { - break - } - p.advance(",") + for p.tkn.Id != ")" && p.tkn.Id != ";" { + a = append(a, p.expression(0)) + if p.tkn.Id != "," { + break } + p.advance(",") } p.advance(")") if left.Id == "." || left.Id == "[" { @@ -293,29 +305,24 @@ func (p *Parser) defineGrammar() { // The object literal notation p.prefix("{", func(sym *Symbol) *Symbol { var a []*Symbol - if p.tkn.Id != "}" { - for { - n := p.tkn - if n.Ar != ArName && n.Ar != ArLiteral { - p.error(n, "bad key") - } - p.advance(_SYM_ANY) - p.advance(":") - v := p.expression(0) - v.Key = n.Val - a = append(a, v) - if p.tkn.Id != "," { - break - } - p.advance(",") - if p.tkn.Id == "}" { - break - } + for p.tkn.Id != "}" && p.tkn.Id != ";" { + n := p.tkn + if n.Ar != ArName && n.Ar != ArLiteral { + p.error(n, "bad key") } + p.advance(_SYM_ANY) + p.advance(":") + v := p.expression(0) + v.Key = n.Val + a = append(a, v) + if p.tkn.Id != "," { + break + } + p.advance(",") } p.advance("}") sym.First = a - sym.Ar = ArUnary + sym.Ar = ArLiteral return sym }) diff --git a/runtime/funcvm.go b/runtime/funcvm.go index 7d4a740..7135af6 100644 --- a/runtime/funcvm.go +++ b/runtime/funcvm.go @@ -455,9 +455,16 @@ func (f *agoraFuncVM) run(args ...Val) Val { case bytecode.OP_NEW: ob := NewObject() - for j := ix; j > 0; j-- { - key, val := f.pop(), f.pop() - ob.Set(key, val) + if flg == bytecode.FLG_Fn2 { + for j := ix; j > 0; j-- { + key, val := f.pop(), f.pop() + ob.Set(key, val) + } + } else if flg == bytecode.FLG_Fn { + for j := ix; j > 0; j-- { + val := f.pop() + ob.Set(Number(j-1), val) + } } f.push(ob) diff --git a/testdata/src/82-array.agora b/testdata/src/82-array.agora new file mode 100644 index 0000000..9c35155 --- /dev/null +++ b/testdata/src/82-array.agora @@ -0,0 +1,6 @@ +/*--- +output: {1:2,0:1}\n +---*/ +fmt := import("fmt") +a := [1, 2] +fmt.Println(a)