basic for loop + examples -> era3
This commit is contained in:
parent
dd7af341a3
commit
0bc8b2ef55
24 changed files with 222 additions and 201 deletions
|
|
@ -153,6 +153,7 @@ func (c *Compiler) add(instruction Bytecode) {
|
|||
c.advance(1)
|
||||
}
|
||||
|
||||
// addConstant add both a constant (if it is not already defined), and add the index of it to the bytecode
|
||||
func (c *Compiler) addConstant(value Value) {
|
||||
chunk := c.Chunk
|
||||
for i := 0; i < len(chunk.Constants); i++ {
|
||||
|
|
@ -165,6 +166,10 @@ func (c *Compiler) addConstant(value Value) {
|
|||
|
||||
chunk.Constants = append(chunk.Constants, value)
|
||||
|
||||
if len(chunk.Constants) > 256 {
|
||||
panic("too many constants (>256)")
|
||||
}
|
||||
|
||||
c.add(Bytecode(len(chunk.Constants) - 1))
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +477,6 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
|||
c.add(InstructionJumpFalse)
|
||||
jumpValuePos = c.ip
|
||||
c.advance(2)
|
||||
|
||||
}
|
||||
|
||||
c.add(InstructionPop)
|
||||
|
|
@ -492,6 +496,74 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
|||
|
||||
return &CompositeSignature{dt, &NilSignature{}}, nil
|
||||
|
||||
case ForNodeType:
|
||||
n := tree.(*ForNode)
|
||||
|
||||
is, err := c.compile(n.iterator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iteratorSignature := &FunctionSignature{
|
||||
[]TypeSignature{},
|
||||
&TupleSignature{
|
||||
[]TypeSignature{
|
||||
&AnySignature{},
|
||||
&BooleanSignature{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !iteratorSignature.Contains(is) {
|
||||
return nil, c.error(fmt.Sprintf("cannot iterate with non-iterator %s (must be %s)", is, iteratorSignature), n.iterator)
|
||||
}
|
||||
|
||||
outputSig := is.(*FunctionSignature).Out.(*TupleSignature).Contents[0]
|
||||
ipos := c.ip
|
||||
|
||||
c.addDescend()
|
||||
c.add(InstructionDuplicate)
|
||||
c.add(InstructionCall)
|
||||
c.add(InstructionDestructureTuple)
|
||||
|
||||
// if no more items; jump to end
|
||||
c.add(InstructionJumpFalse)
|
||||
jmpValuePos := c.ip
|
||||
c.advance(2)
|
||||
|
||||
if n.counter.Type() != ReferenceNodeType {
|
||||
return nil, c.error("cannot use non-variable as a counter", n.counter)
|
||||
}
|
||||
|
||||
name := n.counter.(*ReferenceNode).name
|
||||
|
||||
c.add(InstructionDeclareLocal)
|
||||
c.addConstant(&StringValue{
|
||||
name,
|
||||
})
|
||||
c.add(InstructionPop)
|
||||
c.registerVar(name, outputSig)
|
||||
|
||||
_, err = c.compile(n.logic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.add(InstructionPop)
|
||||
|
||||
c.addAscend()
|
||||
|
||||
c.add(InstructionLoop)
|
||||
c.addU16(uint16(c.ip - ipos + 2))
|
||||
|
||||
// end of loop
|
||||
c.putU16(jmpValuePos, uint16(c.ip-jmpValuePos-2))
|
||||
|
||||
c.add(InstructionPop)
|
||||
c.add(InstructionPop)
|
||||
c.add(InstructionNil)
|
||||
|
||||
return &NilSignature{}, nil
|
||||
|
||||
case AssignNodeType:
|
||||
n := tree.(*AssignNode)
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ const (
|
|||
TokenElse
|
||||
TokenImport
|
||||
TokenType
|
||||
TokenFor
|
||||
TokenIn
|
||||
|
||||
TokenComma
|
||||
TokenDot
|
||||
|
|
@ -178,6 +180,10 @@ func (t TokenKind) String() string {
|
|||
return "newline"
|
||||
case TokenType:
|
||||
return "type"
|
||||
case TokenFor:
|
||||
return "for"
|
||||
case TokenIn:
|
||||
return "in"
|
||||
}
|
||||
|
||||
panic("UNDEFINED TOKENTYPE STRING CONVERSION")
|
||||
|
|
@ -196,6 +202,8 @@ var Keywords = map[string]TokenKind{
|
|||
"while": TokenWhile,
|
||||
"breakpoint": TokenBreakpoint,
|
||||
"type": TokenType,
|
||||
"for": TokenFor,
|
||||
"in": TokenIn,
|
||||
}
|
||||
|
||||
type Lexer struct {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const (
|
|||
BlockNodeType
|
||||
ConditionalNodeType
|
||||
LoopNodeType
|
||||
ForNodeType
|
||||
AssignNodeType
|
||||
InvokeNodeType
|
||||
CallNodeType
|
||||
|
|
@ -501,7 +502,7 @@ func (n ConditionalNode) Bounds() (Pos, Pos) {
|
|||
return n.start, n.end
|
||||
}
|
||||
|
||||
// LoopNode Loops (for/while)
|
||||
// LoopNode While loops
|
||||
type LoopNode struct {
|
||||
condition Node
|
||||
do Node
|
||||
|
|
@ -522,6 +523,28 @@ func (n LoopNode) Bounds() (Pos, Pos) {
|
|||
return n.start, n.end
|
||||
}
|
||||
|
||||
// ForNode For loops
|
||||
type ForNode struct {
|
||||
counter Node
|
||||
iterator Node
|
||||
logic Node
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
}
|
||||
|
||||
func (n ForNode) Type() NodeType {
|
||||
return ForNodeType
|
||||
}
|
||||
|
||||
func (n ForNode) String() string {
|
||||
return fmt.Sprintf("for %s in %s; %s", n.counter, n.iterator, n.logic)
|
||||
}
|
||||
|
||||
func (n ForNode) Bounds() (Pos, Pos) {
|
||||
return n.start, n.end
|
||||
}
|
||||
|
||||
// AssignNode assignment
|
||||
type AssignNode struct {
|
||||
dest Node
|
||||
|
|
|
|||
|
|
@ -383,6 +383,38 @@ func (p *Parser) expression(mustBeBlock bool) (Node, error) {
|
|||
p.prev.End,
|
||||
}, nil
|
||||
|
||||
case TokenFor:
|
||||
p.advance()
|
||||
start := p.prev.Start
|
||||
|
||||
counter, err := p.expression(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := p.expect(TokenIn, "for-loops must be for each item in an iterator"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iterator, err := p.expression(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logic, err := p.expression(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ForNode{
|
||||
counter,
|
||||
iterator,
|
||||
logic,
|
||||
|
||||
start,
|
||||
p.prev.End,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
s, err := p.binary()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -742,7 +742,7 @@ func (v *BuiltinFunctionValue) Type() ValueType {
|
|||
}
|
||||
|
||||
func (v *BuiltinFunctionValue) String() string {
|
||||
return fmt.Sprintf("<function name=%s builtin>", v.Name)
|
||||
return fmt.Sprintf("<function builtin name=%s>", v.Name)
|
||||
}
|
||||
|
||||
func (v *BuiltinFunctionValue) DebugString() string {
|
||||
|
|
|
|||
17
core/vm.go
17
core/vm.go
|
|
@ -133,6 +133,9 @@ const (
|
|||
// InstructionFormTuple pop n+1 (u16) items from the stack, and create a new tuple with the items. The top value
|
||||
// on the stack is the last value in the tuple.
|
||||
InstructionFormTuple
|
||||
// InstructionDestructureTuple pop a tuple, and push all its items to the stack, with the top item on the stack
|
||||
// being the last item in the tuple.
|
||||
InstructionDestructureTuple
|
||||
|
||||
// InstructionIndexList index into a list. The lower item is the container, and the top item
|
||||
// is the index. [..., container, index] -> [..., item]
|
||||
|
|
@ -251,6 +254,8 @@ func (b Bytecode) String() string {
|
|||
return "INDEX_LIST"
|
||||
case InstructionIndexTuple:
|
||||
return "INDEX_TUPLE"
|
||||
case InstructionDestructureTuple:
|
||||
return "DESTRUCTURE_TUPLE"
|
||||
}
|
||||
return "UNDEFINED"
|
||||
}
|
||||
|
|
@ -605,10 +610,7 @@ var DefaultGlobals = map[string]Value{
|
|||
&StringSignature{},
|
||||
),
|
||||
},
|
||||
quickComposite(
|
||||
&FloatSignature{},
|
||||
&NilSignature{},
|
||||
),
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, _ Value, args []Value) (Value, error) {
|
||||
switch v := args[0].(type) {
|
||||
|
|
@ -620,7 +622,7 @@ var DefaultGlobals = map[string]Value{
|
|||
case *StringValue:
|
||||
num, err := strconv.ParseFloat(v.Text, FloatSize)
|
||||
if err != nil {
|
||||
return &NilValue{}, nil
|
||||
return &FloatValue{}, nil
|
||||
}
|
||||
|
||||
return &FloatValue{num}, nil
|
||||
|
|
@ -1014,6 +1016,11 @@ func (vm *VM) Next() bool {
|
|||
items,
|
||||
})
|
||||
|
||||
case InstructionDestructureTuple:
|
||||
t := vm.Stack.Pop().(*TupleValue)
|
||||
|
||||
vm.Stack.Push(t.Items...)
|
||||
|
||||
case InstructionDescend:
|
||||
vm.descend()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue