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