adding immutable value (incomplete)
This commit is contained in:
parent
a1bd73f238
commit
19498da491
7 changed files with 85 additions and 2 deletions
compiler
docs
runtime
29
compiler/ast/immutable_expr.go
Normal file
29
compiler/ast/immutable_expr.go
Normal 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() + ")"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue