adding immutable value (incomplete)

This commit is contained in:
Daniel Kang 2019-01-24 19:31:17 -08:00
parent a1bd73f238
commit 19498da491
7 changed files with 85 additions and 2 deletions

View file

@ -0,0 +1,29 @@
package ast
import (
"github.com/d5/tengo/compiler/source"
)
// ImmutableExpr represents an immutable expression
type ImmutableExpr struct {
Expr Expr
ErrorPos source.Pos
LParen source.Pos
RParen source.Pos
}
func (e *ImmutableExpr) exprNode() {}
// Pos returns the position of first character belonging to the node.
func (e *ImmutableExpr) Pos() source.Pos {
return e.ErrorPos
}
// End returns the position of first character immediately after the node.
func (e *ImmutableExpr) End() source.Pos {
return e.RParen
}
func (e *ImmutableExpr) String() string {
return "immutable(" + e.Expr.String() + ")"
}

View file

@ -473,6 +473,13 @@ func (c *Compiler) Compile(node ast.Node) error {
}
c.emit(OpError)
case *ast.ImmutableExpr:
if err := c.Compile(node.Expr); err != nil {
return err
}
c.emit(OpImmutable)
}
return nil

View file

@ -35,6 +35,7 @@ const (
OpArray // Array object
OpMap // Map object
OpError // Error object
OpImmutable // Immutable object
OpIndex // Index operation
OpSliceIndex // Slice operation
OpCall // Call function
@ -94,6 +95,7 @@ var OpcodeNames = [...]string{
OpArray: "ARR",
OpMap: "MAP",
OpError: "ERROR",
OpImmutable: "IMMUT",
OpIndex: "INDEX",
OpSliceIndex: "SLICE",
OpCall: "CALL",
@ -150,6 +152,7 @@ var OpcodeOperands = [...][]int{
OpArray: {2},
OpMap: {2},
OpError: {},
OpImmutable: {},
OpIndex: {},
OpSliceIndex: {},
OpCall: {1},

View file

@ -361,6 +361,9 @@ func (p *Parser) parseOperand() ast.Expr {
case token.Error: // error expression
return p.parseErrorExpr()
case token.Immutable: // immutable expression
return p.parseImmutableExpr()
}
pos := p.pos
@ -483,6 +486,25 @@ func (p *Parser) parseErrorExpr() ast.Expr {
return expr
}
func (p *Parser) parseImmutableExpr() ast.Expr {
pos := p.pos
p.next()
lparen := p.expect(token.LParen)
value := p.parseExpr()
rparen := p.expect(token.RParen)
expr := &ast.ImmutableExpr{
ErrorPos: pos,
Expr: value,
LParen: lparen,
RParen: rparen,
}
return expr
}
func (p *Parser) parseFuncType() *ast.FuncType {
if p.trace {
defer un(trace(p, "FuncType"))
@ -572,7 +594,7 @@ func (p *Parser) parseStmt() (stmt ast.Stmt) {
switch p.token {
case // simple statements
token.Func, token.Error, token.Ident, token.Int, token.Float, token.Char, token.String, token.True, token.False,
token.Func, token.Error, token.Immutable, token.Ident, token.Int, token.Float, token.Char, token.String, token.True, token.False,
token.Undefined, token.Import, token.LParen, token.LBrace, token.LBrack,
token.Add, token.Sub, token.Mul, token.And, token.Xor, token.Not:
s := p.parseSimpleStmt(false)

View file

@ -74,6 +74,7 @@ const (
For
Func
Error
Immutable
If
Return
Switch
@ -149,6 +150,7 @@ var tokens = [...]string{
For: "for",
Func: "func",
Error: "error",
Immutable: "immutable",
If: "if",
Return: "return",
Switch: "switch",

View file

@ -150,9 +150,26 @@ for k, v in {k1: 1, k2: 2} { // map: key and value
}
```
## Immutable Values
A value can be marked as immutable using `immutable` expression.
```golang
a := immutable([1, 2, 3]) // 'a' is immutable
b = a[1] // b == 2
a[0] = 5 // runtime error
c := immutable({d: [1, 2, 3]})
c.d[1] = 10 // runtime error as 'c.d' is also immutable
e := {f: a} // 'a' is immutable but 'e' is not
e.g = 20 // valid; e == {f: a, g: 20}
e.a[1] = 5 // runtime error as 'e.a' is immutable
```
## Errors
An error object is created using `error` function-like keyword. An error can have any types of value and the underlying value of the error can be accessed using `.value` selector.
An error object is created using `error` expression. An error can contain value of any types, and, the underlying value can be read using `.value` selector.
```golang
err1 := error("oops") // error with string value

View file

@ -562,6 +562,9 @@ func (v *VM) Run() error {
v.stack[v.sp] = &err
v.sp++
case compiler.OpImmutable:
// TODO: implement here
case compiler.OpIndex:
index := v.stack[v.sp-1]
left := v.stack[v.sp-2]