Basic type system working
This commit is contained in:
parent
3f260e7ffd
commit
84cc845748
19 changed files with 900 additions and 131 deletions
|
|
@ -22,13 +22,22 @@ func GetAllTestCases() map[string]AllTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"func": {
|
"func": {
|
||||||
"func sum(a, b) {\n\treturn a + b\n}\nsum(1, 2)",
|
"func sum(a: number, b: number) {\n\treturn a + b\n}\nsum(1, 2)",
|
||||||
[]Value{
|
[]Value{
|
||||||
&VariableValue{
|
&VariableValue{
|
||||||
"sum",
|
"sum",
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "sum",
|
Name: "sum",
|
||||||
Params: []string{"a", "b"},
|
Params: []FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
Chunk: &Chunk{
|
Chunk: &Chunk{
|
||||||
Bytecode: []Bytecode{
|
Bytecode: []Bytecode{
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
|
|
|
||||||
171
core/compiler.go
171
core/compiler.go
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,16 +22,18 @@ type ImportsResolver interface {
|
||||||
|
|
||||||
type LocalVariable struct {
|
type LocalVariable struct {
|
||||||
name string
|
name string
|
||||||
|
signature TypeSignature
|
||||||
scope int
|
scope int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompiler() *Compiler {
|
func NewCompiler() *Compiler {
|
||||||
c := &Compiler{
|
c := &Compiler{
|
||||||
Chunk: NewChunk(make([]Bytecode, 0), make([]Value, 0)),
|
NewChunk(make([]Bytecode, 0), make([]Value, 0)),
|
||||||
ip: 0,
|
0,
|
||||||
scope: 0,
|
0,
|
||||||
stack: NewStack[LocalVariable](256),
|
make(map[string]Node),
|
||||||
imports: make(map[string]Node),
|
nil,
|
||||||
|
NewStack[LocalVariable](256),
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
@ -253,8 +256,8 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
// reset instruction pointer (ip)
|
// reset instruction pointer (ip)
|
||||||
c.ip = 0
|
c.ip = 0
|
||||||
|
|
||||||
for _, p := range n.params {
|
for _, p := range n.parameters {
|
||||||
c.registerVar(p)
|
c.registerVar(p.name, p.signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.Compile(n.logic)
|
err := c.Compile(n.logic)
|
||||||
|
|
@ -268,7 +271,7 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
|
|
||||||
mc.Constants[fi] = &FunctionValue{
|
mc.Constants[fi] = &FunctionValue{
|
||||||
n.name,
|
n.name,
|
||||||
n.params,
|
n.parameters,
|
||||||
c.Chunk,
|
c.Chunk,
|
||||||
nil,
|
nil,
|
||||||
}
|
}
|
||||||
|
|
@ -365,6 +368,149 @@ func (c *Compiler) compileBinary(binary *BinaryNode) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
||||||
|
switch tree.Type() {
|
||||||
|
case StringNodeType:
|
||||||
|
return &StringSignature{}, nil
|
||||||
|
case NumberNodeType:
|
||||||
|
return &NumberSignature{}, nil
|
||||||
|
case ReferenceNodeType:
|
||||||
|
return c.getVarSignature(tree.(*ReferenceNode).name)
|
||||||
|
case BooleanNodeType:
|
||||||
|
return &BooleanSignature{}, nil
|
||||||
|
case NilNodeType:
|
||||||
|
return &NilSignature{}, nil
|
||||||
|
case ListNodeType:
|
||||||
|
return &ListSignature{}, nil
|
||||||
|
case BinaryNodeType:
|
||||||
|
n := tree.(*BinaryNode)
|
||||||
|
l, err := c.deduceSignature(n.Left)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r, err := c.deduceSignature(n.Right)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if l != r {
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot perform binary %s on different types: %s and %s", n.BinaryOperation, l, r))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch n.BinaryOperation {
|
||||||
|
case BinarySubtraction, BinaryMultiplication, BinaryDivision:
|
||||||
|
if l.Type() != TypeNumber {
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot perform binary %s non-number type %s", n.BinaryOperation, l))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NumberSignature{}, nil
|
||||||
|
case BinaryAddition:
|
||||||
|
switch l.Type() {
|
||||||
|
case TypeString:
|
||||||
|
return &StringSignature{}, nil
|
||||||
|
case TypeNumber:
|
||||||
|
return &NumberSignature{}, nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot perform binary addition on type %s", l))
|
||||||
|
}
|
||||||
|
case BinaryAnd, BinaryOr:
|
||||||
|
if l.Type() != TypeBoolean {
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot perform binary %s on type %s", l, n.BinaryOperation))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BooleanSignature{}, nil
|
||||||
|
case BinaryEquality, BinaryInequality:
|
||||||
|
return &BooleanSignature{}, nil
|
||||||
|
case BinaryLess, BinaryGreater, BinaryLessEqual, BinaryGreaterEqual:
|
||||||
|
if l.Type() != TypeNumber {
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot perform number comparison (%s) on type %s", l, n.BinaryOperation))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BooleanSignature{}, nil
|
||||||
|
}
|
||||||
|
case AccessNodeType:
|
||||||
|
n := tree.(*AccessNode)
|
||||||
|
sig, err := c.deduceSignature(n.source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sig.Type() {
|
||||||
|
case TypeString, TypeList:
|
||||||
|
case TypeObject:
|
||||||
|
return sig.(*ObjectSignature).members[n.property], nil
|
||||||
|
|
||||||
|
case TypeNumber, TypeBoolean, TypeNil, TypeFunction:
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("cannot access property from value of type %s", sig))
|
||||||
|
}
|
||||||
|
|
||||||
|
case CallNodeType:
|
||||||
|
n := tree.(*CallNode)
|
||||||
|
sig, err := c.deduceSignature(n.source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.Type() != TypeFunction {
|
||||||
|
return nil, errors.New(fmt.Sprintf("cannot call value of type %s", sig.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
f := sig.(*FunctionSignature)
|
||||||
|
|
||||||
|
if len(n.args) != len(f.in) {
|
||||||
|
return nil, errors.New(fmt.Sprintf("bad argument count (expected %v, got %v)", len(f.in), len(n.args)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check arguments
|
||||||
|
for i, arg := range n.args {
|
||||||
|
sig, err := c.deduceSignature(arg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sig.Matches(f.in[i]) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.out, nil
|
||||||
|
|
||||||
|
case FunctionNodeType:
|
||||||
|
n := tree.(*FunctionNode)
|
||||||
|
|
||||||
|
sigs := make([]TypeSignature, len(n.parameters))
|
||||||
|
|
||||||
|
for i, p := range n.parameters {
|
||||||
|
sigs[i] = p.signature
|
||||||
|
}
|
||||||
|
|
||||||
|
return &FunctionSignature{
|
||||||
|
sigs,
|
||||||
|
n.yield,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("unhandled default case")
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("impossible to deduce signature of %s", tree.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) getVarSignature(name string) (TypeSignature, error) {
|
||||||
|
if c.isGlobal(name) {
|
||||||
|
return SignatureOf(DefaultGlobals[name]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := c.stack.Current - 1; i >= 0; i-- {
|
||||||
|
v := c.stack.items[i]
|
||||||
|
if v.name == name {
|
||||||
|
return v.signature, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New(fmt.Sprintf("variable %s not defined", name))
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) getVar(name string) {
|
func (c *Compiler) getVar(name string) {
|
||||||
if c.isGlobal(name) {
|
if c.isGlobal(name) {
|
||||||
c.add(InstructionGetGlobal)
|
c.add(InstructionGetGlobal)
|
||||||
|
|
@ -387,7 +533,11 @@ func (c *Compiler) setVar(name string, value Node, declare bool) error {
|
||||||
|
|
||||||
if declare {
|
if declare {
|
||||||
c.add(InstructionDeclareLocal)
|
c.add(InstructionDeclareLocal)
|
||||||
c.registerVar(name)
|
t, err := c.deduceSignature(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.registerVar(name, t)
|
||||||
} else {
|
} else {
|
||||||
c.add(InstructionSetLocal)
|
c.add(InstructionSetLocal)
|
||||||
}
|
}
|
||||||
|
|
@ -400,9 +550,10 @@ func (c *Compiler) setVar(name string, value Node, declare bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep track that a variable is declared but doesn't necessarily have a deducible type
|
// keep track that a variable is declared but doesn't necessarily have a deducible type
|
||||||
func (c *Compiler) registerVar(name string) {
|
func (c *Compiler) registerVar(name string, t TypeSignature) {
|
||||||
c.stack.Push(LocalVariable{
|
c.stack.Push(LocalVariable{
|
||||||
name,
|
name,
|
||||||
|
t,
|
||||||
int(c.scope),
|
int(c.scope),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,17 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
"sum",
|
"sum",
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
"sum",
|
"sum",
|
||||||
[]string{"a", "b"},
|
[]FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&NumberSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -254,7 +264,16 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
|
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
"sum",
|
"sum",
|
||||||
[]string{"a", "b"},
|
[]FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
NewChunk(
|
NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
|
|
@ -281,7 +300,8 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
"a",
|
"a",
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
"a",
|
"a",
|
||||||
[]string{},
|
[]FunctionParameter{},
|
||||||
|
&NilSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
|
|
@ -311,7 +331,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
"a",
|
"a",
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
"a",
|
"a",
|
||||||
[]string{},
|
[]FunctionParameter{},
|
||||||
NewChunk(
|
NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionDescend,
|
InstructionDescend,
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ const (
|
||||||
|
|
||||||
TokenComma
|
TokenComma
|
||||||
TokenDot
|
TokenDot
|
||||||
|
TokenColon
|
||||||
|
|
||||||
TokenAssign
|
TokenAssign
|
||||||
TokenDeclare
|
TokenDeclare
|
||||||
|
|
@ -153,6 +154,8 @@ func (t TokenType) String() string {
|
||||||
return "close bracket"
|
return "close bracket"
|
||||||
case TokenImport:
|
case TokenImport:
|
||||||
return "import"
|
return "import"
|
||||||
|
case TokenColon:
|
||||||
|
return "colon"
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNDEFINED TOKENTYPE STRING CONVERSION"
|
return "UNDEFINED TOKENTYPE STRING CONVERSION"
|
||||||
|
|
@ -234,11 +237,11 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
case '.':
|
case '.':
|
||||||
return l.makeToken(TokenDot), nil
|
return l.makeToken(TokenDot), nil
|
||||||
case ':':
|
case ':':
|
||||||
if !l.accept('=') {
|
if l.accept('=') {
|
||||||
return l.makeToken(TokenError), errors.New("malformed token (got ':', expected '=' to follow)")
|
return l.makeToken(TokenDeclare), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.makeToken(TokenDeclare), nil
|
return l.makeToken(TokenColon), nil
|
||||||
case '!':
|
case '!':
|
||||||
if l.accept('=') {
|
if l.accept('=') {
|
||||||
return l.makeToken(TokenBangEquals), nil
|
return l.makeToken(TokenBangEquals), nil
|
||||||
|
|
|
||||||
|
|
@ -331,10 +331,16 @@ func (n CallNode) String() string {
|
||||||
// FunctionNode definition of function
|
// FunctionNode definition of function
|
||||||
type FunctionNode struct {
|
type FunctionNode struct {
|
||||||
name string
|
name string
|
||||||
params []string
|
parameters []FunctionParameter
|
||||||
|
yield TypeSignature
|
||||||
logic Node
|
logic Node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FunctionParameter struct {
|
||||||
|
name string
|
||||||
|
signature TypeSignature
|
||||||
|
}
|
||||||
|
|
||||||
func (n FunctionNode) Type() NodeType {
|
func (n FunctionNode) Type() NodeType {
|
||||||
return FunctionNodeType
|
return FunctionNodeType
|
||||||
}
|
}
|
||||||
|
|
|
||||||
108
core/parser.go
108
core/parser.go
|
|
@ -243,6 +243,11 @@ func (p *Parser) factor() (Node, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sig, err := p.parseSignature()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
b, err := p.block(false)
|
b, err := p.block(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -251,6 +256,7 @@ func (p *Parser) factor() (Node, error) {
|
||||||
return &FunctionNode{
|
return &FunctionNode{
|
||||||
"*",
|
"*",
|
||||||
params,
|
params,
|
||||||
|
sig,
|
||||||
b,
|
b,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
|
@ -564,6 +570,8 @@ func (p *Parser) statement() (Node, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield, err := p.parseSignature()
|
||||||
|
|
||||||
b, err := p.block(false)
|
b, err := p.block(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -574,6 +582,7 @@ func (p *Parser) statement() (Node, error) {
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
|
yield,
|
||||||
b,
|
b,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
|
@ -678,15 +687,27 @@ func (p *Parser) parseArgs() ([]Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseParams parse parameters and parentheses
|
// parseParams parse parameters and parentheses
|
||||||
func (p *Parser) parseParams() ([]string, error) {
|
func (p *Parser) parseParams() ([]FunctionParameter, error) {
|
||||||
if err := p.expect(TokenOpenParenthesis); err != nil {
|
if err := p.expect(TokenOpenParenthesis); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
params := make([]string, 0)
|
params := make([]FunctionParameter, 0)
|
||||||
|
|
||||||
if p.accept(TokenName) {
|
if p.accept(TokenName) {
|
||||||
name := (*p.prev).Lexeme
|
name := (*p.prev).Lexeme
|
||||||
params = append(params, name)
|
if err := p.expect(TokenColon); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := p.parseSignature()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
params = append(params, FunctionParameter{
|
||||||
|
name,
|
||||||
|
t,
|
||||||
|
})
|
||||||
for !p.accept(TokenCloseParenthesis) {
|
for !p.accept(TokenCloseParenthesis) {
|
||||||
if err := p.expect(TokenComma); err != nil {
|
if err := p.expect(TokenComma); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -695,7 +716,19 @@ func (p *Parser) parseParams() ([]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
name = (*p.prev).Lexeme
|
name = (*p.prev).Lexeme
|
||||||
params = append(params, name)
|
if err := p.expect(TokenColon); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := p.parseSignature()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
params = append(params, FunctionParameter{
|
||||||
|
name,
|
||||||
|
t,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := p.expect(TokenCloseParenthesis); err != nil {
|
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||||
|
|
@ -705,3 +738,70 @@ func (p *Parser) parseParams() ([]string, error) {
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseSignature() (TypeSignature, error) {
|
||||||
|
if p.accept(TokenFunc) {
|
||||||
|
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var in []TypeSignature
|
||||||
|
|
||||||
|
for !p.accept(TokenCloseParenthesis) && (len(in) == 0 || p.accept(TokenComma)) {
|
||||||
|
sig, err := p.parseSignature()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
in = append(in, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := p.parseSignature()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &FunctionSignature{
|
||||||
|
in,
|
||||||
|
out,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.expect(TokenName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name := (*p.prev).Lexeme
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case "string":
|
||||||
|
return &StringSignature{}, nil
|
||||||
|
case "number":
|
||||||
|
return &NumberSignature{}, nil
|
||||||
|
case "boolean":
|
||||||
|
return &BooleanSignature{}, nil
|
||||||
|
case "list":
|
||||||
|
if err := p.expect(TokenOpenBracket); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contents, err := p.parseSignature()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.expect(TokenCloseBracket); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListSignature{
|
||||||
|
contents,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("unsupported type: " + name)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -338,9 +340,14 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
NewToken(TokenFunc, 3, 4, 0, "func"),
|
NewToken(TokenFunc, 3, 4, 0, "func"),
|
||||||
NewToken(TokenOpenParenthesis, 7, 1, 0, "("),
|
NewToken(TokenOpenParenthesis, 7, 1, 0, "("),
|
||||||
NewToken(TokenName, 8, 1, 0, "a"),
|
NewToken(TokenName, 8, 1, 0, "a"),
|
||||||
|
NewToken(TokenColon, 9, 1, 0, ":"),
|
||||||
|
NewToken(TokenName, 10, 5, 0, "number"),
|
||||||
NewToken(TokenComma, 9, 1, 0, ","),
|
NewToken(TokenComma, 9, 1, 0, ","),
|
||||||
NewToken(TokenName, 10, 1, 0, "b"),
|
NewToken(TokenName, 10, 1, 0, "b"),
|
||||||
|
NewToken(TokenColon, 9, 1, 0, ":"),
|
||||||
|
NewToken(TokenName, 10, 5, 0, "number"),
|
||||||
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
NewToken(TokenCloseParenthesis, 11, 1, 0, ")"),
|
||||||
|
NewToken(TokenName, 10, 5, 0, "number"),
|
||||||
|
|
||||||
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
NewToken(TokenOpenBrace, 12, 1, 1, "{"),
|
||||||
NewToken(TokenReturn, 13, 6, 1, "return"),
|
NewToken(TokenReturn, 13, 6, 1, "return"),
|
||||||
|
|
@ -357,7 +364,17 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
"*",
|
"*",
|
||||||
[]string{"a", "b"},
|
[]FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&NumberSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -404,7 +421,17 @@ func GetTokenTestData() map[string]TokenTestData {
|
||||||
"a",
|
"a",
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
"a",
|
"a",
|
||||||
[]string{"a", "b"},
|
[]FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&NumberSignature{},
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&ReturnNode{
|
&ReturnNode{
|
||||||
|
|
@ -642,15 +669,17 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
||||||
t.Logf("Function node names match (%s)", n.name)
|
t.Logf("Function node names match (%s)", n.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(n.params) != len(m.params) {
|
if len(n.parameters) != len(m.parameters) {
|
||||||
t.Fatalf("Function node parameters count does not match (%d and %d)", len(n.params), len(m.params))
|
t.Fatalf("Function node parameters count does not match (%d and %d)", len(n.parameters), len(m.parameters))
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Function node parameters count is equal (%d) ", len(n.params))
|
t.Logf("Function node parameters count is equal (%d) ", len(n.parameters))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, p := range m.params {
|
for i, p := range m.parameters {
|
||||||
if n.params[i] != p {
|
if !n.parameters[i].signature.Matches(p.signature) {
|
||||||
t.Errorf("Function node parameter %d does not match: %s and %s", i, p, m.params)
|
t.Errorf("Function node parameter signature %d does not match: %s and %s", i, p.signature, n.parameters[i].signature)
|
||||||
|
} else if n.parameters[i].name != p.name {
|
||||||
|
t.Errorf("Function node parameter name %d does not match: %s and %s", i, p.name, n.parameters[i].name)
|
||||||
} else {
|
} else {
|
||||||
t.Logf("Function node parameter %d matches (%s)", i, p)
|
t.Logf("Function node parameter %d matches (%s)", i, p)
|
||||||
}
|
}
|
||||||
|
|
@ -665,6 +694,101 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SerializeTokens(tokens []Token) string {
|
||||||
|
out := strings.Builder{}
|
||||||
|
level := 0
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
switch token.Type {
|
||||||
|
case TokenPlus:
|
||||||
|
out.WriteString(" + ")
|
||||||
|
case TokenMinus:
|
||||||
|
out.WriteString(" - ")
|
||||||
|
case TokenStar:
|
||||||
|
out.WriteString("*")
|
||||||
|
case TokenSlash:
|
||||||
|
out.WriteString("/")
|
||||||
|
case TokenBang:
|
||||||
|
out.WriteString("!")
|
||||||
|
case TokenSemicolon:
|
||||||
|
out.WriteString(";")
|
||||||
|
case TokenNumber:
|
||||||
|
out.WriteString(token.Lexeme)
|
||||||
|
case TokenString:
|
||||||
|
out.WriteString(fmt.Sprintf("\"%s\"", token.Lexeme))
|
||||||
|
case TokenName:
|
||||||
|
out.WriteString(token.Lexeme)
|
||||||
|
case TokenOpenParenthesis:
|
||||||
|
out.WriteString("(")
|
||||||
|
case TokenCloseParenthesis:
|
||||||
|
out.WriteString(")")
|
||||||
|
case TokenOpenBracket:
|
||||||
|
out.WriteString("[")
|
||||||
|
case TokenCloseBracket:
|
||||||
|
out.WriteString("]")
|
||||||
|
case TokenOpenBrace:
|
||||||
|
out.WriteString("{")
|
||||||
|
level = level + 1
|
||||||
|
case TokenCloseBrace:
|
||||||
|
out.WriteString("}")
|
||||||
|
level = level - 1
|
||||||
|
case TokenTrue:
|
||||||
|
out.WriteString("true")
|
||||||
|
case TokenFalse:
|
||||||
|
out.WriteString("false")
|
||||||
|
case TokenNil:
|
||||||
|
out.WriteString("nil")
|
||||||
|
case TokenFunc:
|
||||||
|
out.WriteString("func")
|
||||||
|
case TokenReturn:
|
||||||
|
out.WriteString("return ")
|
||||||
|
case TokenWhile:
|
||||||
|
out.WriteString("while ")
|
||||||
|
case TokenVar:
|
||||||
|
out.WriteString("var ")
|
||||||
|
case TokenIf:
|
||||||
|
out.WriteString("if ")
|
||||||
|
case TokenElse:
|
||||||
|
out.WriteString(" else ")
|
||||||
|
case TokenImport:
|
||||||
|
out.WriteString("import ")
|
||||||
|
case TokenComma:
|
||||||
|
out.WriteString(", ")
|
||||||
|
case TokenDot:
|
||||||
|
out.WriteString(".")
|
||||||
|
case TokenColon:
|
||||||
|
out.WriteString(": ")
|
||||||
|
case TokenAssign:
|
||||||
|
out.WriteString(" = ")
|
||||||
|
case TokenDeclare:
|
||||||
|
out.WriteString(" := ")
|
||||||
|
case TokenBangEquals:
|
||||||
|
out.WriteString(" != ")
|
||||||
|
case TokenEquals:
|
||||||
|
out.WriteString(" == ")
|
||||||
|
case TokenGreaterThan:
|
||||||
|
out.WriteString(" > ")
|
||||||
|
case TokenLessThan:
|
||||||
|
out.WriteString(" < ")
|
||||||
|
case TokenGreaterThanOrEqual:
|
||||||
|
out.WriteString(" >= ")
|
||||||
|
case TokenLessThanOrEqual:
|
||||||
|
out.WriteString(" <= ")
|
||||||
|
case TokenDoubleAmpersand:
|
||||||
|
out.WriteString(" && ")
|
||||||
|
case TokenDoublePipe:
|
||||||
|
out.WriteString(" || ")
|
||||||
|
case TokenBreakpoint:
|
||||||
|
out.WriteString("breakpoint")
|
||||||
|
case TokenEOF:
|
||||||
|
out.WriteString(fmt.Sprintf("<error: \"%s\">", token.Lexeme))
|
||||||
|
case TokenError:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
|
||||||
func TestParser_Parse(t *testing.T) {
|
func TestParser_Parse(t *testing.T) {
|
||||||
t.Logf("Getting test data")
|
t.Logf("Getting test data")
|
||||||
tokenData := GetTokenTestData()
|
tokenData := GetTokenTestData()
|
||||||
|
|
@ -682,7 +806,7 @@ func TestParser_Parse(t *testing.T) {
|
||||||
tree, err := p.Parse()
|
tree, err := p.Parse()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error(s): %s", err.(*ParsingError).Format([]rune{}))
|
t.Fatalf("Unexpected error(s): %s", err.(*ParsingError).Format([]rune(SerializeTokens(data.tokens))))
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Checking parsed tree")
|
t.Logf("Checking parsed tree")
|
||||||
|
|
|
||||||
224
core/types.go
Normal file
224
core/types.go
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeString Type = iota
|
||||||
|
TypeNumber
|
||||||
|
TypeBoolean
|
||||||
|
TypeNil
|
||||||
|
TypeList
|
||||||
|
TypeObject
|
||||||
|
TypeFunction
|
||||||
|
TypeAny
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Type) String() string {
|
||||||
|
switch t {
|
||||||
|
case TypeString:
|
||||||
|
return "String"
|
||||||
|
case TypeNumber:
|
||||||
|
return "Number"
|
||||||
|
case TypeBoolean:
|
||||||
|
return "Boolean"
|
||||||
|
case TypeNil:
|
||||||
|
return "Nil"
|
||||||
|
case TypeList:
|
||||||
|
return "List"
|
||||||
|
case TypeObject:
|
||||||
|
return "Object"
|
||||||
|
case TypeFunction:
|
||||||
|
return "Function"
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("unsupported string conversion for type %v", int(t)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TypeOf(v Value) Type {
|
||||||
|
switch v.(type) {
|
||||||
|
case *StringValue:
|
||||||
|
return TypeString
|
||||||
|
case *NumberValue:
|
||||||
|
return TypeNumber
|
||||||
|
case *BoolValue:
|
||||||
|
return TypeBoolean
|
||||||
|
case *ListValue:
|
||||||
|
return TypeList
|
||||||
|
case *ObjectValue:
|
||||||
|
return TypeObject
|
||||||
|
case *FunctionValue:
|
||||||
|
return TypeFunction
|
||||||
|
case *BuiltinFunctionValue:
|
||||||
|
return TypeFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("unsupported value (of type %T)", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignatureOf(v Value) TypeSignature {
|
||||||
|
switch t := v.(type) {
|
||||||
|
case *StringValue:
|
||||||
|
return &StringSignature{}
|
||||||
|
case *NumberValue:
|
||||||
|
return &NumberSignature{}
|
||||||
|
case *BoolValue:
|
||||||
|
return &BooleanSignature{}
|
||||||
|
case *ListValue:
|
||||||
|
return &ListSignature{}
|
||||||
|
case *ObjectValue:
|
||||||
|
return &ObjectSignature{}
|
||||||
|
case *FunctionValue:
|
||||||
|
return &FunctionSignature{}
|
||||||
|
case *BuiltinFunctionValue:
|
||||||
|
return t.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("unknown value; cannot get signature of %s", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeSignature interface {
|
||||||
|
Type() Type
|
||||||
|
|
||||||
|
// Matches check if this type signature matches another.
|
||||||
|
Matches(TypeSignature) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type NilSignature struct{}
|
||||||
|
|
||||||
|
func (*NilSignature) Type() Type {
|
||||||
|
return TypeNil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NilSignature) Matches(other TypeSignature) bool {
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeNil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringSignature struct{}
|
||||||
|
|
||||||
|
func (*StringSignature) Type() Type {
|
||||||
|
return TypeString
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StringSignature) Matches(other TypeSignature) bool {
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeString
|
||||||
|
}
|
||||||
|
|
||||||
|
type NumberSignature struct{}
|
||||||
|
|
||||||
|
func (*NumberSignature) Type() Type {
|
||||||
|
return TypeNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NumberSignature) Matches(other TypeSignature) bool {
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
type BooleanSignature struct{}
|
||||||
|
|
||||||
|
func (*BooleanSignature) Type() Type {
|
||||||
|
return TypeBoolean
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*BooleanSignature) Matches(other TypeSignature) bool {
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeBoolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListSignature struct {
|
||||||
|
contents TypeSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListSignature) Type() Type {
|
||||||
|
return TypeList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ListSignature) Matches(other TypeSignature) bool {
|
||||||
|
return other.Type() == TypeAny || other.Type() == TypeList && other.(*ListSignature).contents.Matches(s.contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectSignature struct {
|
||||||
|
members map[string]TypeSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ObjectSignature) Type() Type {
|
||||||
|
return TypeObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ObjectSignature) Matches(other TypeSignature) bool {
|
||||||
|
if other.Type() == TypeAny {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Type() != TypeObject {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
o := other.(*ObjectSignature)
|
||||||
|
|
||||||
|
if len(o.members) != len(s.members) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, member := range s.members {
|
||||||
|
v, ok := o.members[name]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.Matches(member) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type FunctionSignature struct {
|
||||||
|
in []TypeSignature
|
||||||
|
out TypeSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*FunctionSignature) Type() Type {
|
||||||
|
return TypeFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FunctionSignature) Matches(other TypeSignature) bool {
|
||||||
|
if other.Type() == TypeAny {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Type() != TypeFunction {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
f := other.(*FunctionSignature)
|
||||||
|
|
||||||
|
if !s.out.Matches(f.out) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f.in) != len(s.in) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, p := range s.in {
|
||||||
|
v := f.in[i]
|
||||||
|
if !p.Matches(v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnySignature struct{}
|
||||||
|
|
||||||
|
func (AnySignature) Type() Type {
|
||||||
|
return TypeAny
|
||||||
|
}
|
||||||
|
|
||||||
|
func (AnySignature) Matches(_ TypeSignature) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
@ -203,12 +203,15 @@ func (v *ObjectValue) Equals(other Value) bool {
|
||||||
var ObjectPrototype = map[string]Value{
|
var ObjectPrototype = map[string]Value{
|
||||||
"set": &BuiltinFunctionValue{
|
"set": &BuiltinFunctionValue{
|
||||||
"set",
|
"set",
|
||||||
[]string{"property", "value"},
|
&FunctionSignature{
|
||||||
func(vm *VM, _this Value, params map[string]Value) (Value, error) {
|
[]TypeSignature{&StringSignature{}, &ListSignature{}},
|
||||||
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, _this Value, params []Value) (Value, error) {
|
||||||
this := _this.(*ObjectValue)
|
this := _this.(*ObjectValue)
|
||||||
|
|
||||||
p := params["property"]
|
p := params[1]
|
||||||
v, ok := params["value"].(*StringValue)
|
v, ok := params[0].(*StringValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("property is not a string")
|
return nil, errors.New("property is not a string")
|
||||||
}
|
}
|
||||||
|
|
@ -282,10 +285,13 @@ func (v *StringValue) Equals(other Value) bool {
|
||||||
var StringPrototype = map[string]*BuiltinFunctionValue{
|
var StringPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"split": {
|
"split": {
|
||||||
"split",
|
"split",
|
||||||
[]string{"seperator"},
|
&FunctionSignature{
|
||||||
func(vm *VM, this Value, m map[string]Value) (Value, error) {
|
[]TypeSignature{&StringSignature{}},
|
||||||
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, this Value, v []Value) (Value, error) {
|
||||||
str := this.(*StringValue).String()
|
str := this.(*StringValue).String()
|
||||||
sep := m["seperator"].(*StringValue).String()
|
sep := v[0].(*StringValue).String()
|
||||||
|
|
||||||
var out []string
|
var out []string
|
||||||
tmp := strings.Builder{}
|
tmp := strings.Builder{}
|
||||||
|
|
@ -361,19 +367,27 @@ func (v *ListValue) Equals(other Value) bool {
|
||||||
var ListPrototype = map[string]*BuiltinFunctionValue{
|
var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
"append": {
|
"append": {
|
||||||
"append",
|
"append",
|
||||||
[]string{"item"},
|
&FunctionSignature{
|
||||||
func(_ *VM, this Value, p map[string]Value) (Value, error) {
|
[]TypeSignature{&AnySignature{}},
|
||||||
this.(*ListValue).items = append(this.(*ListValue).items, p["item"])
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(_ *VM, this Value, v []Value) (Value, error) {
|
||||||
|
this.(*ListValue).items = append(this.(*ListValue).items, v[0])
|
||||||
return &NilValue{}, nil
|
return &NilValue{}, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
"at": {
|
"at": {
|
||||||
"at",
|
"at",
|
||||||
[]string{"index"},
|
&FunctionSignature{
|
||||||
func(_ *VM, this Value, p map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
func(_ *VM, this Value, p []Value) (Value, error) {
|
||||||
items := this.(*ListValue).items
|
items := this.(*ListValue).items
|
||||||
index := int(p["index"].(*NumberValue).float64)
|
index := int(p[0].(*NumberValue).float64)
|
||||||
|
|
||||||
if index >= len(items) {
|
if index >= len(items) {
|
||||||
return nil, errors.New(fmt.Sprintf("list index %x out of range", index))
|
return nil, errors.New(fmt.Sprintf("list index %x out of range", index))
|
||||||
|
|
@ -385,19 +399,32 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
},
|
},
|
||||||
"length": {
|
"length": {
|
||||||
"length",
|
"length",
|
||||||
[]string{},
|
&FunctionSignature{
|
||||||
func(_ *VM, this Value, p map[string]Value) (Value, error) {
|
[]TypeSignature{},
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
func(_ *VM, this Value, _ []Value) (Value, error) {
|
||||||
return GoToValue(len(this.(*ListValue).items)), nil
|
return GoToValue(len(this.(*ListValue).items)), nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
"map": {
|
"map": {
|
||||||
"map",
|
"map",
|
||||||
[]string{"f"},
|
&FunctionSignature{
|
||||||
func(vm *VM, value Value, m map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
|
&FunctionSignature{
|
||||||
|
[]TypeSignature{
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ListSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, value Value, m []Value) (Value, error) {
|
||||||
list := value.(*ListValue)
|
list := value.(*ListValue)
|
||||||
|
|
||||||
v := m["f"]
|
v := m[0]
|
||||||
var f Value
|
var f Value
|
||||||
f, ok := v.(*FunctionValue)
|
f, ok := v.(*FunctionValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -425,11 +452,23 @@ var ListPrototype = map[string]*BuiltinFunctionValue{
|
||||||
},
|
},
|
||||||
"reduce": {
|
"reduce": {
|
||||||
"reduce",
|
"reduce",
|
||||||
[]string{"f", "start"},
|
&FunctionSignature{
|
||||||
func(vm *VM, value Value, m map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
|
&FunctionSignature{
|
||||||
|
[]TypeSignature{
|
||||||
|
&AnySignature{},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, value Value, m []Value) (Value, error) {
|
||||||
list := value.(*ListValue)
|
list := value.(*ListValue)
|
||||||
f := m["f"]
|
f := m[0]
|
||||||
sum := m["start"]
|
sum := m[1]
|
||||||
|
|
||||||
for _, v := range list.items {
|
for _, v := range list.items {
|
||||||
result, err := vm.Call(f, []Value{sum, v})
|
result, err := vm.Call(f, []Value{sum, v})
|
||||||
|
|
@ -455,7 +494,7 @@ func (v *ListValue) Get(key string) (Value, error) {
|
||||||
|
|
||||||
type FunctionValue struct {
|
type FunctionValue struct {
|
||||||
Name string
|
Name string
|
||||||
Params []string
|
Params []FunctionParameter
|
||||||
Chunk *Chunk
|
Chunk *Chunk
|
||||||
Parent Value
|
Parent Value
|
||||||
}
|
}
|
||||||
|
|
@ -484,8 +523,8 @@ func (v *FunctionValue) Get(_ string) (Value, error) {
|
||||||
|
|
||||||
type BuiltinFunctionValue struct {
|
type BuiltinFunctionValue struct {
|
||||||
Name string
|
Name string
|
||||||
Parameters []string
|
Signature *FunctionSignature
|
||||||
F func(*VM, Value, map[string]Value) (Value, error)
|
F func(*VM, Value, []Value) (Value, error)
|
||||||
Parent Value
|
Parent Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,19 +60,10 @@ func CompareValues(t *testing.T, got Value, want Value) {
|
||||||
t.Errorf("builtin function name mismatch: got %v, want %v", n.Name, m.Name)
|
t.Errorf("builtin function name mismatch: got %v, want %v", n.Name, m.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(n.Parameters) != len(m.Parameters) {
|
if !n.Signature.Matches(m.Signature) {
|
||||||
t.Errorf("builtin function parameter count mismatch: got %v, want %v", n.Parameters, m.Parameters)
|
t.Errorf("builtin function parameter count mismatch: got %v, want %v", n, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v := range n.Parameters {
|
|
||||||
if v != m.Parameters[i] {
|
|
||||||
t.Errorf("builtin function parameter %d mismatch: got %v, want %v", i, v, m.Parameters[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if &n.F != &m.F {
|
|
||||||
t.Errorf("builtin function f mismatch: got %v, want %v", &n.F, &m.F)
|
|
||||||
}
|
|
||||||
case VariableValueType:
|
case VariableValueType:
|
||||||
n := got.(*VariableValue)
|
n := got.(*VariableValue)
|
||||||
m := want.(*VariableValue)
|
m := want.(*VariableValue)
|
||||||
|
|
|
||||||
78
core/vm.go
78
core/vm.go
|
|
@ -287,38 +287,56 @@ type Call struct {
|
||||||
var DefaultGlobals = map[string]Value{
|
var DefaultGlobals = map[string]Value{
|
||||||
"write": &BuiltinFunctionValue{
|
"write": &BuiltinFunctionValue{
|
||||||
"write", // always remember where you come from...
|
"write", // always remember where you come from...
|
||||||
[]string{"value"},
|
&FunctionSignature{
|
||||||
func(_ *VM, this Value, v map[string]Value) (Value, error) {
|
[]TypeSignature{&StringSignature{}},
|
||||||
println(v["value"].String())
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(_ *VM, this Value, v []Value) (Value, error) {
|
||||||
|
println(v[0].String())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
"print": &BuiltinFunctionValue{
|
"print": &BuiltinFunctionValue{
|
||||||
"print",
|
"print",
|
||||||
[]string{"value"},
|
&FunctionSignature{
|
||||||
func(_ *VM, this Value, v map[string]Value) (Value, error) {
|
[]TypeSignature{&StringSignature{}},
|
||||||
print(v["value"].String())
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(_ *VM, this Value, v []Value) (Value, error) {
|
||||||
|
print(v[0].String())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
"format": &BuiltinFunctionValue{
|
"format": &BuiltinFunctionValue{
|
||||||
"format",
|
"format",
|
||||||
[]string{"format_string", "values"},
|
&FunctionSignature{
|
||||||
func(vm *VM, value Value, m map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
valuies := m["values"].(*ListValue).items
|
&StringSignature{},
|
||||||
|
&StringSignature{},
|
||||||
|
},
|
||||||
|
&StringSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, value Value, m []Value) (Value, error) {
|
||||||
|
valuies := m[1].(*ListValue).items
|
||||||
|
|
||||||
return GoToValue(fmt.Sprintf(m["format_string"].String(), valuies)), nil
|
return GoToValue(fmt.Sprintf(m[0].String(), valuies)), nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
"assertEq": &BuiltinFunctionValue{
|
"assertEq": &BuiltinFunctionValue{
|
||||||
"assertEq",
|
"assertEq",
|
||||||
[]string{"a", "b"},
|
&FunctionSignature{
|
||||||
func(vm *VM, this Value, params map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
a := params["a"]
|
&AnySignature{},
|
||||||
b := params["b"]
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, this Value, params []Value) (Value, error) {
|
||||||
|
a := params[0]
|
||||||
|
b := params[1]
|
||||||
|
|
||||||
if !a.Equals(b) {
|
if !a.Equals(b) {
|
||||||
return nil, errors.New(fmt.Sprintf("assertion failed: %s does not equal %s", a, b))
|
return nil, errors.New(fmt.Sprintf("assertion failed: %s does not equal %s", a, b))
|
||||||
|
|
@ -330,10 +348,16 @@ var DefaultGlobals = map[string]Value{
|
||||||
},
|
},
|
||||||
"assertNotEq": &BuiltinFunctionValue{
|
"assertNotEq": &BuiltinFunctionValue{
|
||||||
"assertNotEq",
|
"assertNotEq",
|
||||||
[]string{"a", "b"},
|
&FunctionSignature{
|
||||||
func(vm *VM, this Value, params map[string]Value) (Value, error) {
|
[]TypeSignature{
|
||||||
a := params["a"]
|
&AnySignature{},
|
||||||
b := params["b"]
|
&AnySignature{},
|
||||||
|
},
|
||||||
|
&NilSignature{},
|
||||||
|
},
|
||||||
|
func(vm *VM, this Value, params []Value) (Value, error) {
|
||||||
|
a := params[0]
|
||||||
|
b := params[1]
|
||||||
|
|
||||||
if a.Equals(b) {
|
if a.Equals(b) {
|
||||||
return nil, errors.New(fmt.Sprintf("assertion failed: %s does not equal %s", a, b))
|
return nil, errors.New(fmt.Sprintf("assertion failed: %s does not equal %s", a, b))
|
||||||
|
|
@ -479,7 +503,7 @@ func (vm *VM) Next() bool {
|
||||||
for i := len(f.Params) - 1; i >= 0; i-- {
|
for i := len(f.Params) - 1; i >= 0; i-- {
|
||||||
p := vm.stack.Current - Pos(len(f.Params)) + Pos(i)
|
p := vm.stack.Current - Pos(len(f.Params)) + Pos(i)
|
||||||
vm.stack.items[p] = &VariableValue{
|
vm.stack.items[p] = &VariableValue{
|
||||||
f.Params[i],
|
f.Params[i].name,
|
||||||
vm.stack.items[p],
|
vm.stack.items[p],
|
||||||
vm.scope,
|
vm.scope,
|
||||||
}
|
}
|
||||||
|
|
@ -494,10 +518,10 @@ func (vm *VM) Next() bool {
|
||||||
vm.chunk = f.Chunk
|
vm.chunk = f.Chunk
|
||||||
vm.ip = 0
|
vm.ip = 0
|
||||||
case *BuiltinFunctionValue:
|
case *BuiltinFunctionValue:
|
||||||
args := map[string]Value{}
|
args := make([]Value, len(f.Signature.in))
|
||||||
|
|
||||||
for i := len(f.Parameters) - 1; i >= 0; i-- {
|
for i := len(f.Signature.in) - 1; i >= 0; i-- {
|
||||||
args[f.Parameters[i]] = vm.stack.Pop()
|
args[i] = vm.stack.Pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := f.F(vm, f.Parent, args)
|
v, err := f.F(vm, f.Parent, args)
|
||||||
|
|
@ -645,7 +669,7 @@ func (vm *VM) Call(v Value, args []Value) (Value, error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
for i := 0; i < len(f.Params); i++ {
|
for i := 0; i < len(f.Params); i++ {
|
||||||
vm.addVar(f.Params[i], args[i])
|
vm.addVar(f.Params[i].name, args[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Parent != nil {
|
if f.Parent != nil {
|
||||||
|
|
@ -667,13 +691,7 @@ func (vm *VM) Call(v Value, args []Value) (Value, error) {
|
||||||
return vm.stack.Pop(), nil
|
return vm.stack.Pop(), nil
|
||||||
|
|
||||||
case *BuiltinFunctionValue:
|
case *BuiltinFunctionValue:
|
||||||
argies := map[string]Value{}
|
return f.F(vm, f.Parent, args)
|
||||||
|
|
||||||
for i, arg := range args {
|
|
||||||
argies[f.Parameters[i]] = arg
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.F(vm, f.Parent, argies)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(fmt.Sprintf("value is not a function (%s)", v.DebugString()))
|
return nil, errors.New(fmt.Sprintf("value is not a function (%s)", v.DebugString()))
|
||||||
|
|
|
||||||
|
|
@ -442,7 +442,16 @@ func GetExecutionTestData() map[string]struct {
|
||||||
&NumberValue{2},
|
&NumberValue{2},
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "sum",
|
Name: "sum",
|
||||||
Params: []string{"a", "b"},
|
Params: []FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
|
|
@ -476,7 +485,16 @@ func GetExecutionTestData() map[string]struct {
|
||||||
&NumberValue{2},
|
&NumberValue{2},
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "sum",
|
Name: "sum",
|
||||||
Params: []string{"a", "b"},
|
Params: []FunctionParameter{
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
|
|
@ -493,7 +511,12 @@ func GetExecutionTestData() map[string]struct {
|
||||||
},
|
},
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "square",
|
Name: "square",
|
||||||
Params: []string{"n"},
|
Params: []FunctionParameter{
|
||||||
|
{
|
||||||
|
"n",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
|
|
@ -514,7 +537,12 @@ func GetExecutionTestData() map[string]struct {
|
||||||
"square",
|
"square",
|
||||||
&FunctionValue{
|
&FunctionValue{
|
||||||
Name: "square",
|
Name: "square",
|
||||||
Params: []string{"n"},
|
Params: []FunctionParameter{
|
||||||
|
{
|
||||||
|
"n",
|
||||||
|
&NumberSignature{},
|
||||||
|
},
|
||||||
|
},
|
||||||
Chunk: NewChunk(
|
Chunk: NewChunk(
|
||||||
[]Bytecode{
|
[]Bytecode{
|
||||||
InstructionGetLocal, 0,
|
InstructionGetLocal, 0,
|
||||||
|
|
|
||||||
36
examples/pi-approx.py
Normal file
36
examples/pi-approx.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
terms = 100000
|
||||||
|
|
||||||
|
tot = 0
|
||||||
|
|
||||||
|
n = 1
|
||||||
|
while n <= terms:
|
||||||
|
tot = tot + 1 / (n*n)
|
||||||
|
n = n + 1
|
||||||
|
|
||||||
|
tot = tot * 6
|
||||||
|
|
||||||
|
# get the absolute value of a number
|
||||||
|
def abs(x):
|
||||||
|
if x < 0:
|
||||||
|
return -x
|
||||||
|
return x
|
||||||
|
|
||||||
|
# calculate an approximation of the square root of tot using
|
||||||
|
# newton's method.
|
||||||
|
# see: https://en.wikipedia.org/wiki/Newton's_method
|
||||||
|
# The required accuracy
|
||||||
|
SQRT_ACC = 0.00000001
|
||||||
|
def sqrt(x):
|
||||||
|
pg = 0 # previous guess
|
||||||
|
g = 1 # current guess
|
||||||
|
|
||||||
|
while abs(pg - g) >= SQRT_ACC:
|
||||||
|
pg = g
|
||||||
|
g = (pg + tot/pg)/2
|
||||||
|
|
||||||
|
return g
|
||||||
|
|
||||||
|
tot = sqrt(tot)
|
||||||
|
|
||||||
|
# output the result
|
||||||
|
print(tot)
|
||||||
16
examples/pøck.ang
Normal file
16
examples/pøck.ang
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import "math.ang"
|
||||||
|
|
||||||
|
func r_x(t) {
|
||||||
|
return 8*(exp(-t) - t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func r_y(t) {
|
||||||
|
return 5*(exp(-t) - t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func r(t) {
|
||||||
|
return format("(%s, %s)", [r_x(t), r_y(t)])
|
||||||
|
}
|
||||||
|
|
||||||
|
write(r(1))
|
||||||
|
write()
|
||||||
4
lib/util.ang
Normal file
4
lib/util.ang
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
func memoize(f) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,14 +3,14 @@ list := []
|
||||||
x := 1
|
x := 1
|
||||||
while x <= 1000 {
|
while x <= 1000 {
|
||||||
list.append(x)
|
list.append(x)
|
||||||
assertEq(list.reduce(func(tot, a){
|
assertEq(list.reduce(func(tot: number, a: number) number {
|
||||||
return tot + a
|
return tot + a
|
||||||
}, 0), x*(x + 1)/2)
|
}, 0), x*(x + 1)/2)
|
||||||
|
|
||||||
x = x + 1
|
x = x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func sum(a, b) {
|
func sum(a: number, b: number) number {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ E := 2.718281828459045235360287471352
|
||||||
# Get the absolute value of a number. If x is negative, the returned
|
# Get the absolute value of a number. If x is negative, the returned
|
||||||
# value is positive and equal to `-x`. If x is positive or zero, the
|
# value is positive and equal to `-x`. If x is positive or zero, the
|
||||||
# returned value is x.
|
# returned value is x.
|
||||||
func abs(x) {
|
func abs(x: number) number {
|
||||||
# if the number is negative
|
# if the number is negative
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
# negate it so it's positive
|
# negate it so it's positive
|
||||||
|
|
@ -23,7 +23,7 @@ MAX_SQRT_DX := 0.0000001
|
||||||
# x: number
|
# x: number
|
||||||
# Calculate the approximate square root using newton's method until
|
# Calculate the approximate square root using newton's method until
|
||||||
# the accuracy has increased by less than the variable `MAX_SQRT_DX`.
|
# the accuracy has increased by less than the variable `MAX_SQRT_DX`.
|
||||||
func sqrt(x) {
|
func sqrt(x: number) number {
|
||||||
ng := x
|
ng := x
|
||||||
g := 1
|
g := 1
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ func sqrt(x) {
|
||||||
# Return the whole number part of the number. if x is a whole number,
|
# Return the whole number part of the number. if x is a whole number,
|
||||||
# the returned value is x. If x is not a whole number, the closest
|
# the returned value is x. If x is not a whole number, the closest
|
||||||
# whole number which is less than or equal to x is returned.
|
# whole number which is less than or equal to x is returned.
|
||||||
func floor(x) {
|
func floor(x: number) number {
|
||||||
# todo
|
# todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,14 +51,14 @@ func floor(x) {
|
||||||
# Return the whole number part of the number. if x is a whole number,
|
# Return the whole number part of the number. if x is a whole number,
|
||||||
# the returned value is x. If x is not a whole number, the closest
|
# the returned value is x. If x is not a whole number, the closest
|
||||||
# whole number which is greater than or equal to x is returned.
|
# whole number which is greater than or equal to x is returned.
|
||||||
func ceil(x) {
|
func ceil(x: number) number {
|
||||||
# todo
|
# todo
|
||||||
}
|
}
|
||||||
|
|
||||||
# round(x)
|
# round(x)
|
||||||
# x: number
|
# x: number
|
||||||
# Return the closest whole number to the value x.
|
# Return the closest whole number to the value x.
|
||||||
func round(x) {
|
func round(x: number) number {
|
||||||
f := floor(x)
|
f := floor(x)
|
||||||
|
|
||||||
if x - f > 0.5 {
|
if x - f > 0.5 {
|
||||||
|
|
@ -72,7 +72,7 @@ func round(x) {
|
||||||
# x: number; an angle in radians
|
# x: number; an angle in radians
|
||||||
# Get the sine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
# Get the sine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
||||||
# TODO: use hashmap with precomputed values and linear interpolation
|
# TODO: use hashmap with precomputed values and linear interpolation
|
||||||
func sin(x) {
|
func sin(x: number) number {
|
||||||
f := 1
|
f := 1
|
||||||
x = mod(x, 2*PI)
|
x = mod(x, 2*PI)
|
||||||
if x > PI {
|
if x > PI {
|
||||||
|
|
@ -101,14 +101,14 @@ func sin(x) {
|
||||||
# cos(x)
|
# cos(x)
|
||||||
# x: number; an angle in radians
|
# x: number; an angle in radians
|
||||||
# Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
# Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
||||||
func cos(x) {
|
func cos(x: number) number {
|
||||||
# todo
|
# todo
|
||||||
}
|
}
|
||||||
|
|
||||||
# tan(x)
|
# tan(x)
|
||||||
# x: number; an angle in radians
|
# x: number; an angle in radians
|
||||||
# Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent
|
# Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent
|
||||||
func tan(x) {
|
func tan(x: number) number {
|
||||||
# todo
|
# todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ func tan(x) {
|
||||||
# x: number; any number
|
# x: number; any number
|
||||||
# n: number; the number to divide by
|
# n: number; the number to divide by
|
||||||
# Return the rest from a division of x by n.
|
# Return the rest from a division of x by n.
|
||||||
func mod(x, n) {
|
func mod(x: number, n: number) {
|
||||||
if x == 0 {
|
if x == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ func mod(x, n) {
|
||||||
# Get the approximate value of the natural logarithm
|
# Get the approximate value of the natural logarithm
|
||||||
# This function uses newton's method to approximate.
|
# This function uses newton's method to approximate.
|
||||||
LN_ACC := 0.000000001
|
LN_ACC := 0.000000001
|
||||||
func ln(x) {
|
func ln(x: number) number {
|
||||||
pg := 0
|
pg := 0
|
||||||
g := 1
|
g := 1
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ func ln(x) {
|
||||||
# This value is only reasonable if 0<x<1.
|
# This value is only reasonable if 0<x<1.
|
||||||
# It is approximated using the taylor series of e**x.
|
# It is approximated using the taylor series of e**x.
|
||||||
SM_EXP_ACC := 0.00000000001
|
SM_EXP_ACC := 0.00000000001
|
||||||
func sm_exp(x) {
|
func sm_exp(x: number) number {
|
||||||
p_tot := 0
|
p_tot := 0
|
||||||
tot := 1
|
tot := 1
|
||||||
n := 1
|
n := 1
|
||||||
|
|
@ -178,7 +178,7 @@ func sm_exp(x) {
|
||||||
# exp(x)
|
# exp(x)
|
||||||
# x: number; any number
|
# x: number; any number
|
||||||
# Get an approximate value of e raised to the power of x.
|
# Get an approximate value of e raised to the power of x.
|
||||||
func exp(x) {
|
func exp(x: number) number {
|
||||||
n := abs(x)
|
n := abs(x)
|
||||||
tot := 1
|
tot := 1
|
||||||
while n >= 1 {
|
while n >= 1 {
|
||||||
|
|
@ -201,6 +201,6 @@ func exp(x) {
|
||||||
# x: number; any number. The base
|
# x: number; any number. The base
|
||||||
# p: number; the value of the exponent
|
# p: number; the value of the exponent
|
||||||
# Raise any number to any power (x^p)
|
# Raise any number to any power (x^p)
|
||||||
func pow(x, p) {
|
func pow(x: number, p: number) number {
|
||||||
return exp(p*ln(x))
|
return exp(p*ln(x))
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ fibonacci_numbers := [
|
||||||
1346269, 2178309, 3524578, 5702887, 9227465, 14930352
|
1346269, 2178309, 3524578, 5702887, 9227465, 14930352
|
||||||
]
|
]
|
||||||
|
|
||||||
func fib(n) {
|
func fib(n: number) number {
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
func sum(a, b) {
|
func sum(a: number, b: number) number {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue