allow destructuring tuples when assigning
This commit is contained in:
parent
7cb2be8415
commit
91baf28fdf
2 changed files with 73 additions and 26 deletions
|
|
@ -569,23 +569,13 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
|||
case AssignNodeType:
|
||||
n := tree.(*AssignNode)
|
||||
|
||||
switch n.dest.Type() {
|
||||
case ReferenceNodeType:
|
||||
d := n.dest.(*ReferenceNode)
|
||||
|
||||
if d.name == "_" {
|
||||
return c.compile(n.value)
|
||||
}
|
||||
|
||||
if n.declare && c.isVarDeclaredHere(d.name) {
|
||||
return nil, c.error(fmt.Sprintf("%s is already declared in this scope", d.name), n)
|
||||
}
|
||||
|
||||
return c.addSetVar(d.name, n.value, n.declare)
|
||||
default:
|
||||
return nil, c.error(fmt.Sprintf("cannot assign to %s", n.dest.Type()), n.dest)
|
||||
t, err := c.compile(n.value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.compileAssignFromStack(n.dest, t, n.declare)
|
||||
|
||||
case InvokeNodeType:
|
||||
n := tree.(*InvokeNode)
|
||||
|
||||
|
|
@ -635,6 +625,7 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
|||
|
||||
// allow self-referencing
|
||||
sig := n.Signature()
|
||||
c.descend()
|
||||
c.registerVar(n.name, sig)
|
||||
|
||||
// keep track of main chunk
|
||||
|
|
@ -672,6 +663,7 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
|||
return nil, c.error(fmt.Sprintf("yield does not match expected return; got %s, expected %s", yield, c.expectedReturn), causer)
|
||||
}
|
||||
|
||||
c.ascend()
|
||||
c.ascend()
|
||||
|
||||
mc.Constants[fi] = &FunctionValue{
|
||||
|
|
@ -907,6 +899,51 @@ func (c *Compiler) compileBinary(binary *BinaryNode) (TypeSignature, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// compileAssignFromStack assign the value of type sig which is expected to be on top of the stack.
|
||||
func (c *Compiler) compileAssignFromStack(to Node, sig TypeSignature, declare bool) (TypeSignature, error) {
|
||||
switch to.Type() {
|
||||
case ReferenceNodeType:
|
||||
d := to.(*ReferenceNode)
|
||||
|
||||
if d.name == "_" {
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
if declare && c.isVarDeclaredHere(d.name) {
|
||||
return nil, c.error(fmt.Sprintf("%s is already declared in this scope", d.name), to)
|
||||
}
|
||||
|
||||
return c.addSetVar(d.name, sig, declare, to)
|
||||
case TupleNodeType:
|
||||
t := to.(*TupleNode)
|
||||
|
||||
tsig, ok := sig.(*TupleSignature)
|
||||
if !ok {
|
||||
return nil, c.error(fmt.Sprintf("cannot destructure non-tuple %s", sig), to)
|
||||
}
|
||||
|
||||
if len(t.items) != len(tsig.Contents) {
|
||||
return nil, c.error(fmt.Sprintf("not same amount of items; must be %d", len(tsig.Contents)), to)
|
||||
}
|
||||
|
||||
c.add(InstructionDuplicate)
|
||||
c.add(InstructionDestructureTuple)
|
||||
|
||||
// iterate from top to bottom
|
||||
for i := len(t.items) - 1; i >= 0; i-- {
|
||||
_, err := c.compileAssignFromStack(t.items[i], tsig.Contents[i], declare)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.add(InstructionPop)
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
default:
|
||||
return nil, c.error(fmt.Sprintf("cannot assign to %s", to.Type()), to)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) getVarSignature(name string, causer Node) (TypeSignature, error) {
|
||||
if c.isGlobal(name) {
|
||||
return SignatureOf(DefaultGlobals[name]), nil
|
||||
|
|
@ -950,23 +987,20 @@ func (c *Compiler) addGetVar(name string, causer Node) (TypeSignature, error) {
|
|||
return c.getVarSignature(name, causer)
|
||||
}
|
||||
|
||||
func (c *Compiler) addSetVar(name string, value Node, declare bool) (TypeSignature, error) {
|
||||
t, err := c.compile(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// addSetVar add instructions for setting a variable of specified type which is ON TOP OF THE STACK
|
||||
// does also register the variable with the correct type.
|
||||
func (c *Compiler) addSetVar(name string, t TypeSignature, declare bool, causer Node) (TypeSignature, error) {
|
||||
if declare {
|
||||
c.add(InstructionDeclareLocal)
|
||||
c.registerVar(name, t)
|
||||
} else {
|
||||
vt, err := c.getVarSignature(name, value)
|
||||
vt, err := c.getVarSignature(name, causer) // it needs someone to blame >:3
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !vt.Contains(t) {
|
||||
return nil, c.error(fmt.Sprintf("cannot assign value of type %s to variable %s of type %s", t, name, vt), value)
|
||||
return nil, c.error(fmt.Sprintf("cannot assign value of type %s to variable %s of type %s", t, name, vt), causer)
|
||||
}
|
||||
|
||||
c.add(InstructionSetLocal)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
|
||||
# calculate fibonacci numbers with a loop
|
||||
|
||||
(a, b) := (1, 0)
|
||||
for _ in 0..100 {
|
||||
(a, b) = (a + b, b)
|
||||
fn range(from: int, to: int) -> (fn() -> (int, bool)) {
|
||||
i := from - 1
|
||||
end := to - 1
|
||||
|
||||
fn() -> (int, bool) {
|
||||
if i < end {
|
||||
(i = i+1, true)
|
||||
} else {
|
||||
(-1, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(a, b) := (0, 1)
|
||||
for _ in range(0, 100) {
|
||||
(a, b) = (a + b, a)
|
||||
println(a)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue