Compare commits

...

10 commits

33 changed files with 1740 additions and 1976 deletions

40
bad.ang
View file

@ -1,40 +0,0 @@
import "lib/math.ang"
primes := [2]
func is_prime(x: number) boolean {
i := 0
while i < primes.length() && primes.at(i)*primes.at(i) < x {
if mod(x, primes.at(i)) == 0 {
return false
}
i = i + 1
}
return true
}
n := 1
max := 100000
while n < max {
n = n + 2
if is_prime(n) {
primes.append(n)
# Update counter
print(char(0x0D))
print(str(n))
print("/")
print(str(max))
print(char(0x09))
print(str(roundd(n/max*100, 2)))
print("%")
print(char(0x09))
print(str(primes.length()))
print(" primes")
}
}
write(str(primes))

View file

@ -1,15 +0,0 @@
MAX_WIDTH := 16
print(" ")
w := 1
n := 0x21
while n < 0xA0 {
print(char(n))
n = n + 1
w = w + 1
if w >= MAX_WIDTH {
write("")
w = 0
}
}

View file

@ -150,7 +150,8 @@ func makeChunk(ctx *Context, fpath string, ignoreWarnings bool) (*core.Chunk, er
if ctx.Debug { if ctx.Debug {
log.Println("Compiling parse tree") log.Println("Compiling parse tree")
} }
err = c.Compile(tree)
_, err = c.Compile(tree)
if err != nil { if err != nil {
var e core.FormatedError var e core.FormatedError
if errors.As(err, &e) { if errors.As(err, &e) {
@ -296,7 +297,7 @@ func (cmd *ReplCmd) Run(ctx *Context) error {
} }
c.SetSource(src) c.SetSource(src)
if err = c.Compile(prog); err != nil { if _, err = c.Compile(prog); err != nil {
var e core.FormatedError var e core.FormatedError
if errors.As(err, &e) { if errors.As(err, &e) {
log.Print(e.Format()) log.Print(e.Format())

View file

@ -1,24 +0,0 @@
passphrase := "Hello world!".split("")
start := [0, 0, 0]
modulus := 10
base := byte("!")
i := 0
n := 0
while n < passphrase.length() {
b := byte(passphrase.at(n))
v = start.at(i) + b - base
while v >= modulus {
v = v - modulus
}
start.put(i, v)
if i >= 3 {
i = 0
}
n = n + 1
}

File diff suppressed because it is too large Load diff

View file

@ -7,24 +7,29 @@ import (
) )
type Token struct { type Token struct {
Type TokenType Type TokenKind
Start Pos Start Pos
End Pos End Pos
Line Pos Line Pos
Lexeme string Lexeme string
} }
func (t Token) Bounds() (Pos, Pos) {
return t.Start, t.End
}
func (t Token) String() string { func (t Token) String() string {
return fmt.Sprintf("token %s, '%s' %d -> %d, line %d", t.Type.String(), t.Lexeme, t.Start, t.End, t.Line) return fmt.Sprintf("token %s, '%s' %d -> %d, line %d", t.Type.String(), t.Lexeme, t.Start, t.End, t.Line)
} }
type TokenType uint64 type TokenKind uint64
const ( const (
TokenPlus TokenType = iota TokenPlus TokenKind = iota
TokenMinus TokenMinus
TokenStar TokenStar
TokenSlash TokenSlash
TokenPercent
TokenBang TokenBang
TokenSemicolon TokenSemicolon
@ -51,7 +56,10 @@ const (
TokenVar TokenVar
TokenIf TokenIf
TokenElse TokenElse
TokenImport TokenInclude
TokenType
TokenFor
TokenIn
TokenComma TokenComma
TokenDot TokenDot
@ -77,7 +85,7 @@ const (
TokenError TokenError
) )
func (t TokenType) String() string { func (t TokenKind) String() string {
switch t { switch t {
case TokenPlus: case TokenPlus:
return "plus" return "plus"
@ -159,8 +167,8 @@ func (t TokenType) String() string {
return "open bracket" return "open bracket"
case TokenCloseBracket: case TokenCloseBracket:
return "close bracket" return "close bracket"
case TokenImport: case TokenInclude:
return "import" return "include"
case TokenColon: case TokenColon:
return "colon" return "colon"
case TokenPipe: case TokenPipe:
@ -171,11 +179,34 @@ func (t TokenType) String() string {
return "arrow" return "arrow"
case TokenNewLine: case TokenNewLine:
return "newline" return "newline"
case TokenType:
return "type"
case TokenFor:
return "for"
case TokenIn:
return "in"
} }
panic("UNDEFINED TOKENTYPE STRING CONVERSION") panic("UNDEFINED TOKENTYPE STRING CONVERSION")
} }
var Keywords = map[string]TokenKind{
"true": TokenTrue,
"false": TokenFalse,
"nil": TokenNil,
"if": TokenIf,
"else": TokenElse,
"include": TokenInclude,
"var": TokenVar,
"fn": TokenFunc,
"return": TokenReturn,
"while": TokenWhile,
"breakpoint": TokenBreakpoint,
"type": TokenType,
"for": TokenFor,
"in": TokenIn,
}
type Lexer struct { type Lexer struct {
src []rune src []rune
start Pos start Pos
@ -238,6 +269,8 @@ func (l *Lexer) NextToken() (Token, error) {
} }
return l.makeToken(TokenSlash), nil return l.makeToken(TokenSlash), nil
case '%':
return l.makeToken(TokenPercent), nil
case '(': case '(':
return l.makeToken(TokenOpenParenthesis), nil return l.makeToken(TokenOpenParenthesis), nil
case ')': case ')':
@ -340,32 +373,12 @@ func (l *Lexer) NextToken() (Token, error) {
l.advance() l.advance()
} }
switch string(l.src[l.start:l.current]) { lexeme := string(l.src[l.start:l.current])
case "true": if k, ok := Keywords[lexeme]; ok {
return l.makeToken(TokenTrue), nil return l.makeToken(k), nil
case "false":
return l.makeToken(TokenFalse), nil
case "nil":
return l.makeToken(TokenNil), nil
case "if":
return l.makeToken(TokenIf), nil
case "else":
return l.makeToken(TokenElse), nil
case "var":
return l.makeToken(TokenVar), nil
case "fn":
return l.makeToken(TokenFunc), nil
case "while":
return l.makeToken(TokenWhile), nil
case "breakpoint":
return l.makeToken(TokenBreakpoint), nil
case "return":
return l.makeToken(TokenReturn), nil
case "import":
return l.makeToken(TokenImport), nil
default:
return l.makeToken(TokenName), nil
} }
return l.makeToken(TokenName), nil
} else if c == '0' && l.peek() != '.' { } else if c == '0' && l.peek() != '.' {
if l.peek() == 'x' { if l.peek() == 'x' {
l.advance() l.advance()
@ -400,7 +413,7 @@ func (l *Lexer) NextToken() (Token, error) {
} }
} }
func NewToken(t TokenType, start Pos, end Pos, line Pos, lexeme string) Token { func NewToken(t TokenKind, start Pos, end Pos, line Pos, lexeme string) Token {
return Token{ return Token{
Type: t, Type: t,
Start: start, Start: start,
@ -425,7 +438,7 @@ func (l *Lexer) Tokenize() ([]Token, error) {
return tokens, err return tokens, err
} }
func (l *Lexer) makeToken(t TokenType) Token { func (l *Lexer) makeToken(t TokenKind) Token {
return NewToken(t, l.start, l.current, l.line, string(l.src[l.start:l.current])) return NewToken(t, l.start, l.current, l.line, string(l.src[l.start:l.current]))
} }

View file

@ -6,37 +6,37 @@ import (
type LexerTestData struct { type LexerTestData struct {
source string source string
expectedTokens []TokenType expectedTokens []TokenKind
} }
func GetLexerTestData() map[string]LexerTestData { func GetLexerTestData() map[string]LexerTestData {
return map[string]LexerTestData{ return map[string]LexerTestData{
"hello_world_string(1)": { "hello_world_string(1)": {
"\"Hello world\"", "\"Hello world\"",
[]TokenType{TokenString, TokenEOF}, []TokenKind{TokenString, TokenEOF},
}, },
"empty_string(1)": { "empty_string(1)": {
"\"\"", "\"\"",
[]TokenType{TokenString, TokenEOF}, []TokenKind{TokenString, TokenEOF},
}, },
"simple number(1)": { "simple number(1)": {
"1024", "1024",
[]TokenType{TokenInteger, TokenEOF}, []TokenKind{TokenInteger, TokenEOF},
}, },
"simple_arithmetics(7)": { "simple_arithmetics(7)": {
"1 + 23 / 4 * 3", "1 + 23 / 4 * 3",
[]TokenType{ []TokenKind{
TokenInteger, TokenPlus, TokenInteger, TokenSlash, TokenInteger, TokenPlus, TokenInteger, TokenSlash,
TokenInteger, TokenStar, TokenInteger, TokenEOF, TokenInteger, TokenStar, TokenInteger, TokenEOF,
}, },
}, },
"condition(3)": { "condition(3)": {
"a <= 200", "a <= 200",
[]TokenType{TokenName, TokenLessThanOrEqual, TokenInteger, TokenEOF}, []TokenKind{TokenName, TokenLessThanOrEqual, TokenInteger, TokenEOF},
}, },
"if_statement(10)": { "if_statement(10)": {
"if a >= 200 {\n write(\"Hello world!\")\n}", "if a >= 200 {\n write(\"Hello world!\")\n}",
[]TokenType{ []TokenKind{
TokenIf, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenOpenBrace, TokenNewLine, TokenIf, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenOpenBrace, TokenNewLine,
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine,
TokenCloseBrace, TokenEOF, TokenCloseBrace, TokenEOF,
@ -44,7 +44,7 @@ func GetLexerTestData() map[string]LexerTestData {
}, },
"if_else_statement(20)": { "if_else_statement(20)": {
"if 23 * 2/3 > 32 {\n write(\"It is larger!\")\n} else {\n write(\"It is lower!\")\n}", "if 23 * 2/3 > 32 {\n write(\"It is larger!\")\n} else {\n write(\"It is lower!\")\n}",
[]TokenType{ []TokenKind{
TokenIf, TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger, TokenGreaterThan, TokenInteger, TokenOpenBrace, TokenNewLine, TokenIf, TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger, TokenGreaterThan, TokenInteger, TokenOpenBrace, TokenNewLine,
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine, TokenCloseBrace, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine, TokenCloseBrace,
TokenElse, TokenOpenBrace, TokenNewLine, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine, TokenCloseBrace, TokenElse, TokenOpenBrace, TokenNewLine, TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine, TokenCloseBrace,
@ -53,11 +53,11 @@ func GetLexerTestData() map[string]LexerTestData {
}, },
"empty_string": { "empty_string": {
"", "",
[]TokenType{TokenEOF}, []TokenKind{TokenEOF},
}, },
"full_arithmetic_equality": { "full_arithmetic_equality": {
"a + 2 == 10 * 2 / 3", "a + 2 == 10 * 2 / 3",
[]TokenType{ []TokenKind{
TokenName, TokenPlus, TokenInteger, TokenEquals, TokenName, TokenPlus, TokenInteger, TokenEquals,
TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger, TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger,
TokenEOF, TokenEOF,
@ -65,11 +65,11 @@ func GetLexerTestData() map[string]LexerTestData {
}, },
"name": { "name": {
"print", "print",
[]TokenType{TokenName, TokenEOF}, []TokenKind{TokenName, TokenEOF},
}, },
"bunch_of_parentheses": { "bunch_of_parentheses": {
"(((())))", "(((())))",
[]TokenType{ []TokenKind{
TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis,
TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis,
TokenEOF, TokenEOF,
@ -77,22 +77,22 @@ func GetLexerTestData() map[string]LexerTestData {
}, },
"space_before_string": { "space_before_string": {
"\n \"\"", "\n \"\"",
[]TokenType{TokenNewLine, TokenString, TokenEOF}, []TokenKind{TokenNewLine, TokenString, TokenEOF},
}, },
"write_call": { "write_call": {
"write(\"Hello world\")", "write(\"Hello world\")",
[]TokenType{TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenEOF}, []TokenKind{TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenEOF},
}, },
"complex_comparison": { "complex_comparison": {
"!(h__elo123 >= 1)", "!(h__elo123 >= 1)",
[]TokenType{ []TokenKind{
TokenBang, TokenOpenParenthesis, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenCloseParenthesis, TokenBang, TokenOpenParenthesis, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenCloseParenthesis,
TokenEOF, TokenEOF,
}, },
}, },
"3assignments_1condition": { "3assignments_1condition": {
"a = 8 * 32\nb = a > 256\nc = a <= 256\n!b == c", "a = 8 * 32\nb = a > 256\nc = a <= 256\n!b == c",
[]TokenType{ []TokenKind{
TokenName, TokenAssign, TokenInteger, TokenStar, TokenInteger, TokenNewLine, TokenName, TokenAssign, TokenInteger, TokenStar, TokenInteger, TokenNewLine,
TokenName, TokenAssign, TokenName, TokenGreaterThan, TokenInteger, TokenNewLine, TokenName, TokenAssign, TokenName, TokenGreaterThan, TokenInteger, TokenNewLine,
TokenName, TokenAssign, TokenName, TokenLessThanOrEqual, TokenInteger, TokenNewLine, TokenName, TokenAssign, TokenName, TokenLessThanOrEqual, TokenInteger, TokenNewLine,
@ -101,14 +101,14 @@ func GetLexerTestData() map[string]LexerTestData {
}, },
"function": { "function": {
"fn sum(a, b) {\n return a + b\n}", "fn sum(a, b) {\n return a + b\n}",
[]TokenType{ []TokenKind{
TokenFunc, TokenName, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis, TokenFunc, TokenName, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace, TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace,
}, },
}, },
"while_loop": { "while_loop": {
"while a < 5 {\n a = a + 1\n}", "while a < 5 {\n a = a + 1\n}",
[]TokenType{ []TokenKind{
TokenWhile, TokenName, TokenLessThan, TokenInteger, TokenOpenBrace, TokenNewLine, TokenWhile, TokenName, TokenLessThan, TokenInteger, TokenOpenBrace, TokenNewLine,
TokenName, TokenAssign, TokenName, TokenPlus, TokenInteger, TokenNewLine, TokenCloseBrace, TokenEOF, TokenName, TokenAssign, TokenName, TokenPlus, TokenInteger, TokenNewLine, TokenCloseBrace, TokenEOF,
}, },
@ -117,14 +117,14 @@ func GetLexerTestData() map[string]LexerTestData {
"sum := fn(a, b) {\n" + "sum := fn(a, b) {\n" +
" return a + b\n" + " return a + b\n" +
"}", "}",
[]TokenType{ []TokenKind{
TokenName, TokenDeclare, TokenFunc, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis, TokenName, TokenDeclare, TokenFunc, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace, TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace,
}, },
}, },
"list": { "list": {
"data := [3, 1, 4, 1]", "data := [3, 1, 4, 1]",
[]TokenType{ []TokenKind{
TokenName, TokenDeclare, TokenOpenBracket, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenCloseBracket, TokenName, TokenDeclare, TokenOpenBracket, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenCloseBracket,
}, },
}, },

View file

@ -16,7 +16,7 @@ type Node interface {
Bounds() (Pos, Pos) Bounds() (Pos, Pos)
} }
type Boundary interface { type Bounded interface {
Bounds() (Pos, Pos) Bounds() (Pos, Pos)
} }
@ -34,12 +34,16 @@ const (
BlockNodeType BlockNodeType
ConditionalNodeType ConditionalNodeType
LoopNodeType LoopNodeType
ForNodeType
AssignNodeType AssignNodeType
InvokeNodeType InvokeNodeType
CallNodeType CallNodeType
FunctionNodeType FunctionNodeType
ReturnNodeType ReturnNodeType
AccessNodeType AccessNodeType
AliasNodeType
IndexNodeType
IncludeNodeType
BreakpointNodeType BreakpointNodeType
) )
@ -68,7 +72,7 @@ func (n NodeType) String() string {
case AssignNodeType: case AssignNodeType:
return "Assign" return "Assign"
case InvokeNodeType: case InvokeNodeType:
return "Call" return "Invoke"
case FunctionNodeType: case FunctionNodeType:
return "Function" return "Function"
case ReturnNodeType: case ReturnNodeType:
@ -85,6 +89,10 @@ func (n NodeType) String() string {
return "Unary" return "Unary"
case CallNodeType: case CallNodeType:
return "Call" return "Call"
case AliasNodeType:
return "Alias"
case IndexNodeType:
return "Index"
} }
return "Invalid Node Type" return "Invalid Node Type"
} }
@ -231,7 +239,7 @@ func (n TupleNode) Bounds() (Pos, Pos) {
type AccessNode struct { type AccessNode struct {
source Node source Node
property string property *Token
start Pos start Pos
end Pos end Pos
@ -242,7 +250,7 @@ func (n AccessNode) Type() NodeType {
} }
func (n AccessNode) String() string { func (n AccessNode) String() string {
return fmt.Sprintf("(%s from %s)", n.property, n.source) return fmt.Sprintf("(%s from %s)", n.property.Lexeme, n.source)
} }
func (n AccessNode) Bounds() (Pos, Pos) { func (n AccessNode) Bounds() (Pos, Pos) {
@ -273,9 +281,9 @@ func (n BinaryOperation) String() string {
return "less or equal" return "less or equal"
case BinaryGreaterEqual: case BinaryGreaterEqual:
return "greater or equal" return "greater or equal"
case BinaryAnd: case BinaryBooleanAnd:
return "and" return "and"
case BinaryOr: case BinaryBooleanOr:
return "or" return "or"
} }
@ -287,9 +295,10 @@ const (
BinarySubtraction BinarySubtraction
BinaryMultiplication BinaryMultiplication
BinaryDivision BinaryDivision
BinaryModulo
BinaryAnd BinaryBooleanAnd
BinaryOr BinaryBooleanOr
// Comparison // Comparison
BinaryEquality BinaryEquality
@ -310,6 +319,8 @@ func (n BinaryOperation) Symbol() string {
return "*" return "*"
case BinaryDivision: case BinaryDivision:
return "/" return "/"
case BinaryModulo:
return "%"
case BinaryEquality: case BinaryEquality:
return "==" return "=="
case BinaryInequality: case BinaryInequality:
@ -322,9 +333,9 @@ func (n BinaryOperation) Symbol() string {
return "<=" return "<="
case BinaryGreaterEqual: case BinaryGreaterEqual:
return ">=" return ">="
case BinaryAnd: case BinaryBooleanAnd:
return "&&" return "&&"
case BinaryOr: case BinaryBooleanOr:
return "||" return "||"
} }
@ -337,6 +348,7 @@ type BinaryNode struct {
Left Node Left Node
Right Node Right Node
operator *Token
start Pos start Pos
end Pos end Pos
} }
@ -386,6 +398,7 @@ type UnaryNode struct {
UnaryOperation UnaryOperation
value Node value Node
operator *Token
start Pos start Pos
end Pos end Pos
} }
@ -404,7 +417,7 @@ func (n UnaryNode) Bounds() (Pos, Pos) {
// BooleanNode boolean value // BooleanNode boolean value
type BooleanNode struct { type BooleanNode struct {
value bool Boolean bool
start Pos start Pos
end Pos end Pos
@ -415,7 +428,7 @@ func (n BooleanNode) Type() NodeType {
} }
func (n BooleanNode) String() string { func (n BooleanNode) String() string {
return strconv.FormatBool(n.value) return strconv.FormatBool(n.Boolean)
} }
func (n BooleanNode) Bounds() (Pos, Pos) { func (n BooleanNode) Bounds() (Pos, Pos) {
@ -493,7 +506,7 @@ func (n ConditionalNode) Bounds() (Pos, Pos) {
return n.start, n.end return n.start, n.end
} }
// LoopNode Loops (for/while) // LoopNode While loops
type LoopNode struct { type LoopNode struct {
condition Node condition Node
do Node do Node
@ -514,6 +527,28 @@ func (n LoopNode) Bounds() (Pos, Pos) {
return n.start, n.end 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 // AssignNode assignment
type AssignNode struct { type AssignNode struct {
dest Node dest Node
@ -560,7 +595,7 @@ func (n InvokeNode) Bounds() (Pos, Pos) {
// CallNode call a function of a value // CallNode call a function of a value
type CallNode struct { type CallNode struct {
source Node source Node
name Token name *Token
args []Node args []Node
start Pos start Pos
@ -607,6 +642,18 @@ func (n FunctionNode) Bounds() (Pos, Pos) {
return n.start, n.end return n.start, n.end
} }
func (n FunctionNode) Signature() *FunctionSignature {
args := make([]TypeSignature, len(n.parameters))
for i, p := range n.parameters {
args[i] = p.Signature
}
return &FunctionSignature{
args,
n.yield,
}
}
// ReturnNode return a value out of this context // ReturnNode return a value out of this context
type ReturnNode struct { type ReturnNode struct {
value Node value Node
@ -627,6 +674,65 @@ func (n ReturnNode) Bounds() (Pos, Pos) {
return n.start, n.end return n.start, n.end
} }
type AliasNode struct {
name *Token
signature TypeSignature
start Pos
end Pos
}
func (n AliasNode) Type() NodeType {
return AliasNodeType
}
func (n AliasNode) String() string {
return fmt.Sprintf("alias %s to be %s", n.name, n.signature)
}
func (n AliasNode) Bounds() (Pos, Pos) {
return n.start, n.end
}
type IncludeNode struct {
path *StringNode
start Pos
end Pos
}
func (n IncludeNode) Type() NodeType {
return IncludeNodeType
}
func (n IncludeNode) String() string {
return fmt.Sprintf("include \"%s\"", n.path)
}
func (n IncludeNode) Bounds() (Pos, Pos) {
return n.start, n.end
}
type IndexNode struct {
source Node
index Node
start Pos
end Pos
}
func (n IndexNode) Type() NodeType {
return IndexNodeType
}
func (n IndexNode) String() string {
return fmt.Sprintf("index %s of %s", n.source.String(), n.index)
}
func (n IndexNode) Bounds() (Pos, Pos) {
return n.start, n.end
}
type BreakpointNode struct { type BreakpointNode struct {
start Pos start Pos
end Pos end Pos

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
package core package core
import ( import (
"fmt" "math/big"
"strconv" "strconv"
"strings"
"testing" "testing"
) )
@ -74,6 +73,7 @@ func GetTokenTestData() map[string]TokenTestData {
2, 2,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
false, false,
@ -129,6 +129,7 @@ func GetTokenTestData() map[string]TokenTestData {
"b", "b",
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
true, true,
@ -190,12 +191,14 @@ func GetTokenTestData() map[string]TokenTestData {
1, 1,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
&FloatNode{ &FloatNode{
5, 5,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
&BinaryNode{ &BinaryNode{
@ -214,10 +217,13 @@ func GetTokenTestData() map[string]TokenTestData {
2, 2,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
&BinaryNode{ &BinaryNode{
@ -230,8 +236,10 @@ func GetTokenTestData() map[string]TokenTestData {
2, 2,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
false, false,
@ -264,6 +272,7 @@ func GetTokenTestData() map[string]TokenTestData {
15, 15,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
false, false,
@ -299,6 +308,7 @@ func GetTokenTestData() map[string]TokenTestData {
0, 0,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
do: &BlockNode{ do: &BlockNode{
@ -352,6 +362,7 @@ func GetTokenTestData() map[string]TokenTestData {
0, 0,
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
do: &BlockNode{ do: &BlockNode{
@ -459,6 +470,7 @@ func GetTokenTestData() map[string]TokenTestData {
"b", "b",
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
0, 0, 0, 0,
@ -530,6 +542,7 @@ func GetTokenTestData() map[string]TokenTestData {
"b", "b",
0, 0, 0, 0,
}, },
nil,
0, 0, 0, 0,
}, },
0, 0, 0, 0,
@ -565,7 +578,7 @@ func GetTokenTestData() map[string]TokenTestData {
"a", "a",
0, 0, 0, 0,
}, },
"b", &Token{TokenName, 0, 1, 0, "b"},
0, 0, 0, 0,
}, },
true, true,
@ -651,6 +664,57 @@ func GetTokenTestData() map[string]TokenTestData {
0, 0, 0, 0,
}, },
}, },
"single_tuple": {
[]Token{
NewToken(TokenOpenParenthesis, 0, 0, 0, "("),
NewToken(TokenInteger, 0, 0, 0, "1"),
NewToken(TokenComma, 0, 0, 0, ","),
NewToken(TokenCloseParenthesis, 0, 0, 0, ")"),
NewToken(TokenEOF, 0, 0, 0, ""),
},
&BlockNode{
[]Node{
&TupleNode{
[]Node{
&IntegerNode{
big.NewInt(1),
0, 0,
},
},
0, 0,
},
},
0, 0,
},
},
"tuple": {
[]Token{
NewToken(TokenOpenParenthesis, 0, 0, 0, "("),
NewToken(TokenInteger, 0, 0, 0, "1"),
NewToken(TokenComma, 0, 0, 0, ","),
NewToken(TokenInteger, 0, 0, 0, "2"),
NewToken(TokenCloseParenthesis, 0, 0, 0, ")"),
NewToken(TokenEOF, 0, 0, 0, ""),
},
&BlockNode{
[]Node{
&TupleNode{
[]Node{
&IntegerNode{
big.NewInt(1),
0, 0,
},
&IntegerNode{
big.NewInt(2),
0, 0,
},
},
0, 0,
},
},
0, 0,
},
},
} }
} }
@ -717,10 +781,10 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
NodeEquality(t, n1.(*BinaryNode).Right, n2.(*BinaryNode).Right) NodeEquality(t, n1.(*BinaryNode).Right, n2.(*BinaryNode).Right)
case BooleanNodeType: case BooleanNodeType:
if n1.(*BooleanNode).value != n2.(*BooleanNode).value { if n1.(*BooleanNode).Boolean != n2.(*BooleanNode).Boolean {
t.Errorf("Boolean node values don't match (%s and %s)", strconv.FormatBool(n1.(*BooleanNode).value), strconv.FormatBool(n2.(*BooleanNode).value)) t.Errorf("Boolean node values don't match (%s and %s)", strconv.FormatBool(n1.(*BooleanNode).Boolean), strconv.FormatBool(n2.(*BooleanNode).Boolean))
} else { } else {
t.Logf("Boolean node values match (%s)", strconv.FormatBool(n1.(*BooleanNode).value)) t.Logf("Boolean node values match (%s)", strconv.FormatBool(n1.(*BooleanNode).Boolean))
} }
case BlockNodeType: case BlockNodeType:
if len(n1.(*BlockNode).statements) != len(n2.(*BlockNode).statements) { if len(n1.(*BlockNode).statements) != len(n2.(*BlockNode).statements) {
@ -790,7 +854,7 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
} }
for i, p := range m.parameters { for i, p := range m.parameters {
if !n.parameters[i].Signature.Matches(p.Signature) { if !n.parameters[i].Signature.Contains(p.Signature) {
t.Errorf("Function node parameter signature %d does not match: %s and %s", i, p.Signature, n.parameters[i].Signature) 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 { } 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) t.Errorf("Function node parameter name %d does not match: %s and %s", i, p.Name, n.parameters[i].Name)
@ -808,10 +872,11 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
a1 := n1.(*AccessNode) a1 := n1.(*AccessNode)
a2 := n2.(*AccessNode) a2 := n2.(*AccessNode)
if a1.property != a2.property { // only care about lexeme; the rest is debug info
t.Errorf("Access node property does not match: .%s != .%s", a1.property, a2.property) if a1.property.Lexeme != a2.property.Lexeme {
t.Errorf("Access node property does not match: .%s != .%s", a1.property.Lexeme, a2.property.Lexeme)
} else { } else {
t.Logf("Access node property matches: .%s", a1.property) t.Logf("Access node property matches: .%s", a1.property.Lexeme)
} }
NodeEquality(t, a1.source, a2.source) NodeEquality(t, a1.source, a2.source)
@ -825,7 +890,7 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
t.Logf("Both content types are yet to be determined") t.Logf("Both content types are yet to be determined")
} else if l1.content != nil || l2.content != nil { } else if l1.content != nil || l2.content != nil {
t.Errorf("one is nil, one is not") t.Errorf("one is nil, one is not")
} else if !l1.content.Matches(l2.content) { } else if !l1.content.Contains(l2.content) {
t.Errorf("signature doesn't match") t.Errorf("signature doesn't match")
} }
@ -834,110 +899,24 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
NodeEquality(t, v1, l2.items[i]) NodeEquality(t, v1, l2.items[i])
} }
case TupleNodeType:
t1 := n1.(*TupleNode)
t2 := n2.(*TupleNode)
if len(t1.items) != len(t2.items) {
t.Fatalf("tuple item count does not match")
}
for i, v1 := range t1.items {
t.Logf("Checking item %d", i)
NodeEquality(t, v1, t2.items[i])
}
default: default:
panic("unimplemented node equality") panic("unimplemented node equality")
} }
} }
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 TokenFloat:
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("fn")
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 TokenHexadecimal:
out.WriteString(token.Lexeme)
case TokenPipe:
out.WriteString(" | ")
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()
@ -960,6 +939,31 @@ func TestParser_Parse(t *testing.T) {
} }
} }
func TestParser_AcceptAll(t *testing.T) {
p := NewParser("a:", []string{}, []Token{
NewToken(TokenName, 0, 1, 0, "a"),
NewToken(TokenColon, 1, 2, 0, "a"),
})
if !p.acceptAll(TokenName, TokenColon) {
t.Fatalf("tokens were not accepted")
}
t.Logf("tokens were accepted")
}
func TestParser_AcceptAll_TooFew(t *testing.T) {
p := NewParser("a", []string{}, []Token{
NewToken(TokenName, 0, 1, 0, "a"),
})
if p.acceptAll(TokenName, TokenColon) {
t.Fatalf("tokens were incorrectly accepted")
}
t.Logf("tokens were, as expected, not accepted")
}
func BenchmarkParser_Parse(b *testing.B) { func BenchmarkParser_Parse(b *testing.B) {
tokenData := GetTokenTestData() tokenData := GetTokenTestData()

View file

@ -14,11 +14,13 @@ const (
TypeBoolean TypeBoolean
TypeNil TypeNil
TypeList TypeList
TypeTuple
TypeObject TypeObject
TypeFunction TypeFunction
TypeAny TypeAny
TypeComposite TypeComposite
TypeInner TypeInner
TypeNamed
) )
func (t Type) String() string { func (t Type) String() string {
@ -35,6 +37,8 @@ func (t Type) String() string {
return "nil" return "nil"
case TypeList: case TypeList:
return "list" return "list"
case TypeTuple:
return "tuple"
case TypeObject: case TypeObject:
return "object" return "object"
case TypeFunction: case TypeFunction:
@ -68,7 +72,7 @@ func SignatureOf(v Value) TypeSignature {
sig := SignatureOf(p) sig := SignatureOf(p)
if contains == nil { if contains == nil {
contains = sig contains = sig
} else if !contains.Matches(sig) { } else if !contains.Contains(sig) {
contains = &AnySignature{} contains = &AnySignature{}
break break
} }
@ -92,6 +96,16 @@ func SignatureOf(v Value) TypeSignature {
} }
case *BuiltinFunctionValue: case *BuiltinFunctionValue:
return t.Signature return t.Signature
case *TupleValue:
var contains []TypeSignature
for _, p := range t.Items {
sig := SignatureOf(p)
contains = append(contains, sig)
}
return &TupleSignature{
contains,
}
} }
panic(fmt.Sprintf("unknown value; cannot get signature of %s", v)) panic(fmt.Sprintf("unknown value; cannot get signature of %s", v))
@ -100,8 +114,12 @@ func SignatureOf(v Value) TypeSignature {
type TypeSignature interface { type TypeSignature interface {
Type() Type Type() Type
// Matches check if this type signature matches another. // Contains check if this type signature matches another.
Matches(TypeSignature) bool // For it to return true, the other type should be a part of this.
Contains(TypeSignature) bool
// Equal check if the other signature is the EXACT SAME as this one.
Equal(TypeSignature) bool
// String create a human-readable string version of the value type. // String create a human-readable string version of the value type.
String() string String() string
@ -113,12 +131,12 @@ func (*NilSignature) Type() Type {
return TypeNil return TypeNil
} }
func (s *NilSignature) Matches(other TypeSignature) bool { func (s *NilSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeNil
return other.Matches(s)
} }
return other.Type() == TypeAny || other.Type() == TypeNil func (s *NilSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeNil
} }
func (*NilSignature) String() string { func (*NilSignature) String() string {
@ -131,16 +149,16 @@ func (*StringSignature) Type() Type {
return TypeString return TypeString
} }
func (s *StringSignature) Matches(other TypeSignature) bool { func (s *StringSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeString
return other.Matches(s)
} }
return other.Type() == TypeAny || other.Type() == TypeString func (s *StringSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeString
} }
func (*StringSignature) String() string { func (*StringSignature) String() string {
return "string" return "str"
} }
type FloatSignature struct{} type FloatSignature struct{}
@ -149,12 +167,12 @@ func (*FloatSignature) Type() Type {
return TypeFloat return TypeFloat
} }
func (s *FloatSignature) Matches(other TypeSignature) bool { func (s *FloatSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeFloat
return other.Matches(s)
} }
return other.Type() == TypeAny || other.Type() == TypeFloat func (s *FloatSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeFloat
} }
func (*FloatSignature) String() string { func (*FloatSignature) String() string {
@ -167,12 +185,12 @@ func (*IntegerSignature) Type() Type {
return TypeInteger return TypeInteger
} }
func (s *IntegerSignature) Matches(other TypeSignature) bool { func (s *IntegerSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeInteger
return other.Matches(s)
} }
return other.Type() == TypeAny || other.Type() == TypeInteger func (s *IntegerSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeInteger
} }
func (*IntegerSignature) String() string { func (*IntegerSignature) String() string {
@ -185,12 +203,12 @@ func (*BooleanSignature) Type() Type {
return TypeBoolean return TypeBoolean
} }
func (s *BooleanSignature) Matches(other TypeSignature) bool { func (s *BooleanSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeBoolean
return other.Matches(s)
} }
return other.Type() == TypeAny || other.Type() == TypeBoolean func (s *BooleanSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeBoolean
} }
func (*BooleanSignature) String() string { func (*BooleanSignature) String() string {
@ -205,16 +223,75 @@ func (*ListSignature) Type() Type {
return TypeList return TypeList
} }
func (s *ListSignature) Matches(other TypeSignature) bool { func (s *ListSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite { return other.Type() == TypeList && other.(*ListSignature).Contents.Contains(s.Contents)
return other.Matches(s)
} }
return other.Type() == TypeAny || (other.Type() == TypeList && other.(*ListSignature).Contents.Matches(s.Contents)) func (s *ListSignature) Equal(other TypeSignature) bool {
return other.Type() == TypeList && other.(*ListSignature).Contents.Equal(s.Contents)
} }
func (s *ListSignature) String() string { func (s *ListSignature) String() string {
return fmt.Sprintf("list[%s]", s.Contents) return fmt.Sprintf("[%s]", s.Contents)
}
type TupleSignature struct {
Contents []TypeSignature
}
func (*TupleSignature) Type() Type {
return TypeTuple
}
func (s *TupleSignature) Contains(other TypeSignature) bool {
if other.Type() != TypeTuple || len(other.(*TupleSignature).Contents) != len(s.Contents) {
return false
}
n := other.(*TupleSignature).Contents
for i, c := range s.Contents {
if !c.Contains(n[i]) {
return false
}
}
return true
}
func (s *TupleSignature) Equal(other TypeSignature) bool {
if other.Type() != TypeTuple {
return false
}
n := other.(*TupleSignature).Contents
for i, c := range s.Contents {
if !c.Equal(n[i]) {
return false
}
}
return true
}
func (s *TupleSignature) String() string {
sb := strings.Builder{}
sb.WriteString("(")
for i, t := range s.Contents {
if i > 0 {
sb.WriteString(",")
sb.WriteString(" ")
}
sb.WriteString(t.String())
}
if len(s.Contents) <= 1 {
sb.WriteString(",")
}
sb.WriteString(")")
return sb.String()
} }
type ObjectSignature struct { type ObjectSignature struct {
@ -225,25 +302,13 @@ func (*ObjectSignature) Type() Type {
return TypeObject return TypeObject
} }
func (s *ObjectSignature) Matches(other TypeSignature) bool { func (s *ObjectSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite {
return other.Matches(s)
}
if other.Type() == TypeAny {
return true
}
if other.Type() != TypeObject { if other.Type() != TypeObject {
return false return false
} }
o := other.(*ObjectSignature) o := other.(*ObjectSignature)
if len(o.Members) != len(s.Members) {
return false
}
for name, member := range s.Members { for name, member := range s.Members {
v, ok := o.Members[name] v, ok := o.Members[name]
@ -251,7 +316,29 @@ func (s *ObjectSignature) Matches(other TypeSignature) bool {
return false return false
} }
if !v.Matches(member) { if !v.Contains(member) {
return false
}
}
return true
}
func (s *ObjectSignature) Equal(other TypeSignature) bool {
if other.Type() != TypeObject {
return false
}
if len(s.Members) != len(other.(*ObjectSignature).Members) {
return false
}
for name, member := range s.Members {
v, ok := other.(*ObjectSignature).Members[name]
if !ok {
return false
}
if !v.Equal(member) {
return false return false
} }
} }
@ -272,22 +359,14 @@ func (*FunctionSignature) Type() Type {
return TypeFunction return TypeFunction
} }
func (s *FunctionSignature) Matches(other TypeSignature) bool { func (s *FunctionSignature) Contains(other TypeSignature) bool {
if other.Type() == TypeComposite {
return other.Matches(s)
}
if other.Type() == TypeAny {
return true
}
if other.Type() != TypeFunction { if other.Type() != TypeFunction {
return false return false
} }
f := other.(*FunctionSignature) f := other.(*FunctionSignature)
if !s.Out.Matches(f.Out) { if !s.Out.Contains(f.Out) {
return false return false
} }
@ -297,7 +376,7 @@ func (s *FunctionSignature) Matches(other TypeSignature) bool {
for i, p := range s.In { for i, p := range s.In {
v := f.In[i] v := f.In[i]
if !p.Matches(v) { if !p.Contains(v) {
return false return false
} }
} }
@ -305,10 +384,30 @@ func (s *FunctionSignature) Matches(other TypeSignature) bool {
return true return true
} }
func (s *FunctionSignature) Equal(other TypeSignature) bool {
if other.Type() != TypeFunction {
return false
}
f := other.(*FunctionSignature)
if len(f.In) != len(s.In) {
return false
}
for i, p := range s.In {
v := f.In[i]
if !p.Equal(v) {
return false
}
}
return f.Out.Equal(s.Out)
}
func (s *FunctionSignature) String() string { func (s *FunctionSignature) String() string {
b := strings.Builder{} b := strings.Builder{}
b.WriteString("func(") b.WriteString("fn(")
for i, t := range s.In { for i, t := range s.In {
if i > 0 { if i > 0 {
@ -319,7 +418,7 @@ func (s *FunctionSignature) String() string {
b.WriteString(")") b.WriteString(")")
if s.Out.Type() != TypeNil { if s.Out.Type() != TypeNil {
b.WriteString(" ") b.WriteString(" -> ")
b.WriteString(s.Out.String()) b.WriteString(s.Out.String())
} }
@ -332,10 +431,14 @@ func (*AnySignature) Type() Type {
return TypeAny return TypeAny
} }
func (*AnySignature) Matches(_ TypeSignature) bool { func (*AnySignature) Contains(_ TypeSignature) bool {
return true return true
} }
func (s *AnySignature) Equal(t TypeSignature) bool {
return t.Type() == TypeAny
}
func (*AnySignature) String() string { func (*AnySignature) String() string {
return "any" return "any"
} }
@ -349,24 +452,72 @@ func (*CompositeSignature) Type() Type {
return TypeComposite return TypeComposite
} }
func (s *CompositeSignature) Matches(other TypeSignature) bool { func (s *CompositeSignature) Contains(other TypeSignature) bool {
return s.A.Matches(other) || s.B.Matches(other) return s.A.Contains(other) || s.B.Contains(other)
}
func (s *CompositeSignature) Equal(t TypeSignature) bool {
return t.Type() == TypeComposite && s.A.Equal(t.(*CompositeSignature).A) && s.B.Equal(t.(*CompositeSignature).B)
} }
func (s *CompositeSignature) String() string { func (s *CompositeSignature) String() string {
return fmt.Sprintf("%s|%s", s.A, s.B) return fmt.Sprintf("%s|%s", s.A, s.B)
} }
func quickComposite(a ...TypeSignature) TypeSignature {
switch len(a) {
case 0:
panic("quick composite: empty array")
case 1:
return a[0]
}
s := a[0]
for i := 1; i < len(a); i++ {
v := a[i]
s = &CompositeSignature{
A: s,
B: v,
}
}
return s
}
type InnerSignature struct{} type InnerSignature struct{}
func (*InnerSignature) Type() Type { func (*InnerSignature) Type() Type {
return TypeInner return TypeInner
} }
func (*InnerSignature) Matches(_ TypeSignature) bool { func (*InnerSignature) Contains(_ TypeSignature) bool {
return false return false
} }
func (s *InnerSignature) Equal(t TypeSignature) bool {
return t.Type() == TypeInner
}
func (*InnerSignature) String() string { func (*InnerSignature) String() string {
return "inner" return "inner"
} }
type NamedSignature struct {
Name string
}
func (*NamedSignature) Type() Type {
return TypeNamed
}
func (s *NamedSignature) Contains(t TypeSignature) bool {
return t.Type() == TypeNamed && s.Name == t.(*NamedSignature).Name
}
func (s *NamedSignature) Equal(t TypeSignature) bool {
return t.Type() == TypeNamed && s.Name == t.(*NamedSignature).Name
}
func (s *NamedSignature) String() string {
return s.Name
}

View file

@ -6,6 +6,7 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"strconv" "strconv"
"strings"
) )
type ValueType int type ValueType int
@ -17,6 +18,7 @@ const (
IntegerValueType IntegerValueType
StringValueType StringValueType
ListValueType ListValueType
TupleValueType
ObjectValueType ObjectValueType
FunctionValueType FunctionValueType
BuiltinFunctionValueType BuiltinFunctionValueType
@ -39,6 +41,8 @@ func (v ValueType) String() string {
return "string" return "string"
case ListValueType: case ListValueType:
return "list" return "list"
case TupleValueType:
return "tuple"
case FunctionValueType: case FunctionValueType:
return "function" return "function"
case BuiltinFunctionValueType: case BuiltinFunctionValueType:
@ -219,8 +223,8 @@ func (v *ObjectValue) Equals(other Value) bool {
return true return true
} }
var ObjectPrototype = map[string]Value{ var ObjectPrototype = map[string]*BuiltinFunctionValue{
"set": &BuiltinFunctionValue{ "set": {
"set", "set",
&FunctionSignature{ &FunctionSignature{
[]TypeSignature{&StringSignature{}, &ListSignature{}}, []TypeSignature{&StringSignature{}, &ListSignature{}},
@ -278,7 +282,12 @@ func (v *FloatValue) Type() ValueType {
} }
func (v *FloatValue) String() string { func (v *FloatValue) String() string {
return strconv.FormatFloat(v.Number, 'g', -1, FloatSize) s := strconv.FormatFloat(v.Number, 'g', -1, FloatSize)
if strings.Index(s, ".") == -1 {
s += ".0"
}
return s
} }
func (v *FloatValue) DebugString() string { func (v *FloatValue) DebugString() string {
@ -597,6 +606,88 @@ func (v *ListValue) Clone() Value {
} }
} }
type TupleValue struct {
Items []Value
}
func (v *TupleValue) Type() ValueType {
return TupleValueType
}
func (v *TupleValue) String() string {
out := "("
for i, item := range v.Items {
if i != 0 {
out += ", "
}
out += item.DebugString()
}
if len(v.Items) <= 1 {
out += ","
}
out += ")"
return out
}
func (v *TupleValue) DebugString() string {
return v.String()
}
func (v *TupleValue) Clone() Value {
n := make([]Value, len(v.Items))
for i, item := range v.Items {
n[i] = item.Clone()
}
return &TupleValue{
n,
}
}
func (v *TupleValue) Equals(other Value) bool {
if other.Type() != TupleValueType {
return false
}
t := other.(*TupleValue).Items
for i, item := range v.Items {
if !item.Equals(t[i]) {
return false
}
}
return true
}
var TuplePrototype = map[string]*BuiltinFunctionValue{
"at": &BuiltinFunctionValue{
"at",
&FunctionSignature{
[]TypeSignature{&IntegerSignature{}},
&InnerSignature{},
},
func(vm *VM, this Value, args []Value) (Value, error) {
i := args[0].(*IntegerValue).Number.Int64()
if i < 0 || i >= int64(len(this.(*TupleValue).Items)) {
return nil, errors.New(fmt.Sprintf("index %x out of range", i))
}
return this.(*TupleValue).Items[i], nil
},
nil,
true,
},
}
func (v *TupleValue) Get(key string) (Value, error) {
if prop, ok := TuplePrototype[key]; ok {
return prop, nil
}
return nil, errors.New(fmt.Sprintf("tuple has no property \"%s\"", key))
}
type FunctionValue struct { type FunctionValue struct {
Name string Name string
Params []FunctionParameter Params []FunctionParameter
@ -651,7 +742,7 @@ func (v *BuiltinFunctionValue) Type() ValueType {
} }
func (v *BuiltinFunctionValue) String() string { 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 { func (v *BuiltinFunctionValue) DebugString() string {

View file

@ -66,7 +66,7 @@ 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 !n.Signature.Matches(m.Signature) { if !n.Signature.Contains(m.Signature) {
t.Errorf("builtin function parameter count mismatch: got %v, want %v", n, m) t.Errorf("builtin function parameter count mismatch: got %v, want %v", n, m)
} }
@ -96,6 +96,19 @@ func CompareValues(t *testing.T, got Value, want Value) {
CompareValues(t, v, m.Members[k]) CompareValues(t, v, m.Members[k])
} }
case TupleValueType:
n := got.(*TupleValue)
m := want.(*TupleValue)
if len(n.Items) != len(m.Items) {
t.Fatalf("tuple item count mismatch: got %d items, want %d items", len(n.Items), len(m.Items))
}
for i, v := range n.Items {
t.Logf("comparing tuple item #%d", i)
CompareValues(t, v, m.Items[i])
}
default: default:
panic("unimplemented comparison") panic("unimplemented comparison")
} }

View file

@ -41,6 +41,8 @@ const (
InstructionMulInt InstructionMulInt
// InstructionDivInt pop two ints and divide the second by the first // InstructionDivInt pop two ints and divide the second by the first
InstructionDivInt InstructionDivInt
// InstructionModInt pop two ints and compute the modulo of the first by the second
InstructionModInt
// InstructionNegateInt negate the int; if it was positive, make it negative, and vice versa. // InstructionNegateInt negate the int; if it was positive, make it negative, and vice versa.
InstructionNegateInt InstructionNegateInt
@ -99,8 +101,8 @@ const (
// InstructionStringConversion Take the top value on the stack and convert it to a string // InstructionStringConversion Take the top value on the stack and convert it to a string
InstructionStringConversion InstructionStringConversion
// InstructionStringConcatenation Add two strings together, with the second value on the stack as left and the top as right // InstructionConcatStrings Add two strings together, with the second value on the stack as left and the top as right
InstructionStringConcatenation InstructionConcatStrings
// InstructionSwap swap the two top items on the stack (1, 2 -> 2, 1) // InstructionSwap swap the two top items on the stack (1, 2 -> 2, 1)
InstructionSwap InstructionSwap
@ -121,17 +123,33 @@ const (
// InstructionNil Push a nil literal to the stack // InstructionNil Push a nil literal to the stack
InstructionNil InstructionNil
// InstructionNewList Push a new (empty) list to the stack
InstructionNewList
// InstructionAppend Append to a list. stack: (... > list > item) => (... > list) // InstructionAppend Append to a list. stack: (... > list > item) => (... > list)
InstructionAppend InstructionAppend
// InstructionFormList Form items on the stack into a list. The 2 bytes after the instructions are the amount of // InstructionFormList Form items on the stack into a list. The 2 bytes after the instructions are the amount of
// items to include minus one. (value of 0 => 1 item, value of 1 => 2 items, etc.) The order is reversed compared // items to include) The order is reversed compared to on the stack; the top value on the stack is the last in the
// to on the stack; the top value on the stack is the last in the list. // list.
InstructionFormList InstructionFormList
// InstructionConcatLists concatenate lists, producing a new list with the values of both lists. Pops two lists. // InstructionConcatLists concatenate lists, producing a new list with the values of both lists. Pops two lists.
InstructionConcatLists InstructionConcatLists
// 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]
InstructionIndexList
// InstructionIndexTuple index into a tuple. The lower item is the container, and the top item
// is the index. [..., container, index] -> [..., item]
InstructionIndexTuple
// InstructionIndexString index into a string. The lower item is the container, and the top item
// is the index. [..., container, index] -> [..., item]. Produces a new string with the character
// at the position
InstructionIndexString
// InstructionBreakpoint for debugging purposes // InstructionBreakpoint for debugging purposes
InstructionBreakpoint InstructionBreakpoint
) )
@ -216,7 +234,7 @@ func (b Bytecode) String() string {
return "ASCEND" return "ASCEND"
case InstructionStringConversion: case InstructionStringConversion:
return "STRING_CONVERSION" return "STRING_CONVERSION"
case InstructionStringConcatenation: case InstructionConcatStrings:
return "STRING_CONCATENATION" return "STRING_CONCATENATION"
case InstructionSwap: case InstructionSwap:
return "SWAP" return "SWAP"
@ -228,8 +246,6 @@ func (b Bytecode) String() string {
return "FORM_LIST" return "FORM_LIST"
case InstructionBreakpoint: case InstructionBreakpoint:
return "BREAKPOINT" return "BREAKPOINT"
case InstructionNewList:
return "NEW_LIST"
case InstructionAppend: case InstructionAppend:
return "APPEND" return "APPEND"
case InstructionAccessProperty: case InstructionAccessProperty:
@ -238,6 +254,14 @@ func (b Bytecode) String() string {
return "CONCAT_LISTS" return "CONCAT_LISTS"
case InstructionDuplicate: case InstructionDuplicate:
return "DUPLICATE" return "DUPLICATE"
case InstructionFormTuple:
return "FORM_TUPLE"
case InstructionIndexList:
return "INDEX_LIST"
case InstructionIndexTuple:
return "INDEX_TUPLE"
case InstructionDestructureTuple:
return "DESTRUCTURE_TUPLE"
} }
return "UNDEFINED" return "UNDEFINED"
} }
@ -247,7 +271,7 @@ type Chunk struct {
Constants []Value Constants []Value
} }
func (c Chunk) String() string { func (c *Chunk) String() string {
b := strings.Builder{} b := strings.Builder{}
b.WriteString("=v= chunk =v=\n") b.WriteString("=v= chunk =v=\n")
@ -320,7 +344,7 @@ func RegisterGOBTypes() {
} }
func (c Chunk) Serialize() []byte { func (c *Chunk) Serialize() []byte {
b := bytes.Buffer{} b := bytes.Buffer{}
e := gob.NewEncoder(&b) e := gob.NewEncoder(&b)
@ -549,7 +573,13 @@ var DefaultGlobals = map[string]Value{
"int": &BuiltinFunctionValue{ "int": &BuiltinFunctionValue{
"int", "int",
&FunctionSignature{ &FunctionSignature{
[]TypeSignature{&AnySignature{}}, []TypeSignature{
quickComposite(
&IntegerSignature{},
&FloatSignature{},
&StringSignature{},
),
},
&CompositeSignature{ &CompositeSignature{
&IntegerSignature{}, &IntegerSignature{},
&NilSignature{}, &NilSignature{},
@ -570,7 +600,7 @@ var DefaultGlobals = map[string]Value{
return &IntegerValue{n}, nil return &IntegerValue{n}, nil
default: default:
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v)) return nil, errors.New(fmt.Sprintf("%s cannot become an integer (undefined)", v))
} }
}, },
nil, nil,
@ -579,35 +609,38 @@ var DefaultGlobals = map[string]Value{
"float": &BuiltinFunctionValue{ "float": &BuiltinFunctionValue{
"float", "float",
&FunctionSignature{ &FunctionSignature{
[]TypeSignature{&AnySignature{}}, []TypeSignature{
&CompositeSignature{ quickComposite(
&FloatSignature{}, &FloatSignature{},
&NilSignature{}, &IntegerSignature{},
&StringSignature{},
),
}, },
&FloatSignature{},
}, },
func(vm *VM, _ Value, args []Value) (Value, error) { func(vm *VM, _ Value, args []Value) (Value, error) {
switch v := args[0].(type) { switch v := args[0].(type) {
case *IntegerValue: case *IntegerValue:
n, _ := v.Number.Float64() n, _ := v.Number.Float64()
return &FloatValue{n}, nil // this might need to clone the value instead return &FloatValue{n}, nil
case *FloatValue: case *FloatValue:
return &FloatValue{v.Number}, nil return v.Clone(), nil
case *StringValue: case *StringValue:
num, err := strconv.ParseFloat(v.Text, FloatSize) num, err := strconv.ParseFloat(v.Text, FloatSize)
if err != nil { if err != nil {
return &NilValue{}, nil return &FloatValue{}, nil
} }
return &FloatValue{num}, nil return &FloatValue{num}, nil
default: default:
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v)) return nil, errors.New(fmt.Sprintf("%s cannot become an integer (undefined)", v))
} }
}, },
nil, nil,
true, true,
}, },
"type": &BuiltinFunctionValue{ "typeof": &BuiltinFunctionValue{
Name: "type", Name: "typeof",
Signature: &FunctionSignature{ Signature: &FunctionSignature{
In: []TypeSignature{&AnySignature{}}, In: []TypeSignature{&AnySignature{}},
Out: &StringSignature{}, Out: &StringSignature{},
@ -660,12 +693,12 @@ var DefaultGlobals = map[string]Value{
"roundd": &BuiltinFunctionValue{ "roundd": &BuiltinFunctionValue{
"roundd", "roundd",
&FunctionSignature{ &FunctionSignature{
[]TypeSignature{&FloatSignature{}, &FloatSignature{}}, []TypeSignature{&FloatSignature{}, &IntegerSignature{}},
&FloatSignature{}, &FloatSignature{},
}, },
func(vm *VM, this Value, args []Value) (Value, error) { func(vm *VM, this Value, args []Value) (Value, error) {
x := args[0].(*FloatValue).Number x := args[0].(*FloatValue).Number
decimals := args[1].(*FloatValue).Number decimals, _ := args[1].(*IntegerValue).Number.Float64()
multiplier := math.Pow(10, decimals) multiplier := math.Pow(10, decimals)
return &FloatValue{math.Round(x*multiplier) / multiplier}, nil return &FloatValue{math.Round(x*multiplier) / multiplier}, nil
}, },
@ -779,6 +812,12 @@ func (vm *VM) Next() bool {
vm.Stack.Push(&IntegerValue{new(big.Int).Div(l, r)}) vm.Stack.Push(&IntegerValue{new(big.Int).Div(l, r)})
case InstructionModInt:
r := vm.Stack.Pop().(*IntegerValue).Number
l := vm.Stack.Pop().(*IntegerValue).Number
vm.Stack.Push(&IntegerValue{new(big.Int).Mod(l, r)})
case InstructionNegateInt: case InstructionNegateInt:
v := vm.Stack.Pop().(*IntegerValue).Number v := vm.Stack.Pop().(*IntegerValue).Number
@ -963,9 +1002,6 @@ func (vm *VM) Next() bool {
items, items,
}) })
case InstructionNewList:
vm.Stack.Push(&ListValue{[]Value{}})
case InstructionAppend: case InstructionAppend:
value := vm.Stack.Pop() value := vm.Stack.Pop()
list := vm.Stack.Pop().(*ListValue) list := vm.Stack.Pop().(*ListValue)
@ -980,6 +1016,23 @@ func (vm *VM) Next() bool {
append(l.Items, r.Items...), append(l.Items, r.Items...),
}) })
case InstructionFormTuple:
n := int(vm.NextU16())
items := make([]Value, n)
for i := n - 1; i >= 0; i-- {
items[i] = vm.Stack.Pop()
}
vm.Stack.Push(&TupleValue{
items,
})
case InstructionDestructureTuple:
t := vm.Stack.Pop().(*TupleValue)
vm.Stack.Push(t.Items...)
case InstructionDescend: case InstructionDescend:
vm.descend() vm.descend()
@ -990,7 +1043,7 @@ func (vm *VM) Next() bool {
v := vm.Stack.Pop() v := vm.Stack.Pop()
vm.Stack.Push(&StringValue{v.String()}) vm.Stack.Push(&StringValue{v.String()})
case InstructionStringConcatenation: case InstructionConcatStrings:
r := vm.Stack.Pop().(*StringValue).Text r := vm.Stack.Pop().(*StringValue).Text
l := vm.Stack.Pop().(*StringValue).Text l := vm.Stack.Pop().(*StringValue).Text
@ -1023,6 +1076,42 @@ func (vm *VM) Next() bool {
vm.Stack.Push(member) vm.Stack.Push(member)
case InstructionIndexList:
i := vm.Stack.Pop().(*IntegerValue)
l := vm.Stack.Pop().(*ListValue)
n := int(i.Number.Int64())
if n < 0 || len(l.Items) <= n {
vm.error(fmt.Sprintf("index %d out of bounds", n))
}
vm.Stack.Push(l.Items[n].Clone())
case InstructionIndexTuple:
i := vm.Stack.Pop().(*IntegerValue)
t := vm.Stack.Pop().(*TupleValue)
n := int(i.Number.Int64())
if n < 0 || len(t.Items) <= n {
vm.error(fmt.Sprintf("index %d out of bounds", n))
}
vm.Stack.Push(t.Items[n].Clone())
case InstructionIndexString:
i := vm.Stack.Pop().(*IntegerValue)
s := vm.Stack.Pop().(*StringValue)
n := int(i.Number.Int64())
if n < 0 || len(s.Text) <= n {
vm.error(fmt.Sprintf("index %d out of bounds", n))
}
vm.Stack.Push(&StringValue{string(s.Text[n])})
case InstructionBreakpoint: case InstructionBreakpoint:
/* /*
// I'm keeping this // I'm keeping this

View file

@ -2,6 +2,7 @@ package core
import ( import (
"fmt" "fmt"
"math/big"
"testing" "testing"
) )
@ -615,6 +616,28 @@ func GetExecutionTestData() map[string]struct {
}, },
[]map[string]Value{}, []map[string]Value{},
}, },
"form_tuple": {
&Chunk{
Bytecode: []Bytecode{
InstructionConstant, 0,
InstructionConstant, 1,
InstructionFormTuple, 0, 2,
},
Constants: []Value{
&IntegerValue{big.NewInt(1)},
&IntegerValue{big.NewInt(2)},
},
},
[]Value{
&TupleValue{
Items: []Value{
&IntegerValue{big.NewInt(1)},
&IntegerValue{big.NewInt(2)},
},
},
},
[]map[string]Value{},
},
} }
} }

View file

@ -1,2 +0,0 @@
write(char(0x12) + char(0x85) + char(0x07))

View file

@ -1,11 +0,0 @@
fn counter() -> (fn() -> int) {
i := 0
fn() -> int { i = i + 1 }
}
next := counter()
println(next())
println(next())
println(next())

View file

@ -1,19 +1,20 @@
write("Bonjour à tout!"); println("Bonjour à tout!")
if 1 == 2 { if 1 == 2 {
# unreachable # unreachable
println("Wooot?? One does equal 2????")
} else { } else {
write("Hooray! One does not equal 2!"); println("Hooray! One does not equal 2!")
} }
for (var n = 1; n < 10; n = n + 1) { for n in 0..10 {
write("Run number " + str(n)); println("Run number " + str(n))
} }
var a = 2; a := 2
write(3 * a*a + 10 / 3); println(3 * a*a + 10 / 3)

View file

@ -1,17 +1,21 @@
# calculate fibonacci numbers with a loop # calculate fibonacci numbers with a loop
x := 0 fn range(from: int, to: int) -> (fn() -> (int, bool)) {
i := from - 1
end := to - 1
n := 1 fn() -> (int, bool) {
p := 1 if i < end {
(i = i+1, true)
while x < 100 { } else {
f := n + p (-1, false)
}
p = n }
n = f }
write(f) (a, b) := (0, 1)
x = x + 1 for _ in range(0, 100) {
(a, b) = (a + b, a)
println(a)
} }

View file

@ -1,6 +1,6 @@
func sum(a, b) { fn sum(a: int, b: int) -> int {
return a + b a + b
} }
write(sum(1, 2)) println(sum(1, 2))

View file

@ -1,4 +1,4 @@
func f(x) { fn f(x) {
return x*x - 4 return x*x - 4
} }

View file

@ -1,13 +1,11 @@
write("Hello world!") println("Hello world!")
a := 1 + 2 a := 1 + 2
println(a)
write(a)
if a > 2 { if a > 2 {
write("Hooray!! a is greater than 2!!!!") println("Hooray!! a is greater than 2!!!!")
} else { } else {
write("oh nooo!!! a is less than or equal to 2!!!!!!!!!!") println("oh nooo!!! a is less than or equal to 2!!!!!!!!!!")
} }

View file

@ -1,3 +1,3 @@
import "math.ang" import "math.ang"
write(sqrt(2)) println(sqrt(2.0))

View file

@ -1,51 +1,47 @@
# Empty list # Empty list
write([]) println([])
# List with items # List with items
write([3, 1, 4, 1, 5, 9, 2, 6, 5]) println([3, 1, 4, 1, 5, 9, 2, 6, 5])
# List with items of different types # List with items of different types
write(["", "私はかっこいいです。", true, nil, nil, 1, 2]) println(["", "私はかっこいいです。", true, nil, nil, 1, 2])
a := [] a := []
a = a.append(1) a = a + [1]
a = a.append(2) a = a + [2]
write(a) println(a)
list := [] list := []
n := 0
x := 0 x := 0
while n < 100 { for n in 0..100 {
x = x + 2*n + 1 x = x + 2*n + 1
list = list.append(x) list = list + [x]
n = n + 1
} }
write(list) println(list)
write(list.map(func(a) { println(list.map(func(a) {
return a - 1 return a - 1
})) }))
write(list.length()) println(list.length())
write(list.at(69)) println(list.at(69))
other := [] other := []
a := 1 for a in 0..=10 {
while a <= 10 {
other = other.append(a) other = other.append(a)
a = a + 1
} }
sum := other.reduce(func(tot, x) { sum := other.reduce(func(tot, x) {
return tot + x return tot + x
}, 0) }, 0)
write(sum) println(sum)
assert(sum == a*(a-1)/2) assert(sum == a*(a-1)/2)

View file

@ -20,9 +20,10 @@ tot = tot * 6.0
# get the absolute value of a number # get the absolute value of a number
fn abs(x: float) -> float { fn abs(x: float) -> float {
if x < 0.0 { if x < 0.0 {
return -x -x
} else {
x
} }
return x
} }
# calculate an approximation of the square root of tot using # calculate an approximation of the square root of tot using

View file

@ -1,16 +1,15 @@
import "math.ang" import "math.ang"
func r_x(t) { fn r_x(t: float) -> float {
return 8*(exp(-t) - t) return 8.0*(exp(-t) - t)
} }
func r_y(t) { fn r_y(t: float) -> float {
return 5*(exp(-t) - t) return 5.0*(exp(-t) - t)
} }
func r(t) { fn r(t: float) -> (float, float) {
return format("(%s, %s)", [r_x(t), r_y(t)]) return (r_x(t), r_y(t))
} }
write(r(1)) println(r(1.0))
write()

View file

@ -1,4 +0,0 @@
import "lib/honning.ang"
write(_bell+_italic+"Hello "+_underline+"world "+_strike+"micheal"+_reset)

15
imp.ang
View file

@ -1,15 +0,0 @@
func is_cool(x: number|string) boolean {
if x == "cool" {
return true
} else if x == 69 {
return true
}
return nil
}
write(str(is_cool("not cool")))
write(str(is_cool("cool")))
write(str(is_cool(0)))
write(str(is_cool(69)))

View file

@ -1,5 +1,5 @@
fn map(list: [any], f: fn(any) -> any) -> [any] { fn (l: list) map(list: [any], f: fn(any) -> any) -> [any] {
out := [] out := []
i := 0 i := 0

View file

@ -9,7 +9,7 @@ E := 2.718281828459045235360287471352
# returned value is x. # returned value is x.
fn absf(x: float) -> float { fn absf(x: float) -> float {
# if the number is negative # if the number is negative
if x < 0 { if x < 0.0 {
# negate it so it's positive # negate it so it's positive
return -x return -x
} }
@ -26,7 +26,7 @@ fn absi(n: int) -> int {
} }
DERIVE_DX := 0.00000001 DERIVE_DX := 0.00000001
fn derive(f: fn(float) -> float, x: float) float { fn derive(f: fn(float) -> float, x: float) -> float {
return (f(x + DERIVE_DX) - f(x))/DERIVE_DX return (f(x + DERIVE_DX) - f(x))/DERIVE_DX
} }
@ -35,7 +35,7 @@ fn newtons(f: fn(float) -> float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(g - pg) > NEWTONS_ACC { while absf(g - pg) > NEWTONS_ACC {
pg = g pg = g
g = pg - f(pg) / derive(f, pg) g = pg - f(pg) / derive(f, pg)
} }
@ -53,12 +53,14 @@ fn sqrt(x: float) -> float {
ng := x ng := x
g := 1.0 g := 1.0
while abs(g - ng) > MAX_SQRT_DX { while absf(g - ng) > MAX_SQRT_DX {
g = ng g = ng
# create new guess # create new guess
ng = (g + x / g) / 2 ng = (g + x / g) / 2.0
} }
g
} }
# floor(x) # floor(x)
@ -82,7 +84,7 @@ fn round(x: float) -> float {
f := floor(x) f := floor(x)
if x - f > 0.5 { if x - f > 0.5 {
return f + 1 return f + 1.0
} }
return f return f
@ -93,16 +95,16 @@ fn round(x: float) -> float {
# 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.
fn mod(x: float, n: float) -> float { fn mod(x: float, n: float) -> float {
if x == 0 { if x == 0.0 {
return 0 return 0.0
} }
if x < 0 { if x < 0.0 {
while x + n <= 0 { while x + n <= 0.0 {
x = x + n x = x + n
} }
} else { } else {
while x - n >= 0 { while x - n >= 0.0 {
x = x - n x = x - n
} }
} }
@ -123,7 +125,7 @@ fn sm_exp(x: float) -> float {
x_pow := x x_pow := x
f := 1.0 f := 1.0
while abs(tot - p_tot) > SM_EXP_ACC { while absf(tot - p_tot) > SM_EXP_ACC {
p_tot = tot p_tot = tot
t := x_pow / f t := x_pow / f
tot = tot + t tot = tot + t
@ -139,18 +141,18 @@ fn sm_exp(x: float) -> float {
# 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.
fn exp(x: float) -> float { fn exp(x: float) -> float {
n := abs(x) n := absf(x)
tot := 1.0 tot := 1.0
while n >= 1 { while n >= 1.0 {
tot = tot * E tot = tot * E
n = n - 1 n = n - 1.0
} }
if n > 0.0 { if n > 0.0 {
tot = tot * sm_exp(n) tot = tot * sm_exp(n)
} }
if x < 0 { if x < 0.0 {
1.0/tot 1.0/tot
} else { } else {
tot tot
@ -166,9 +168,9 @@ fn ln(x: float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(pg - g) > LN_ACC { while absf(pg - g) > LN_ACC {
pg = g pg = g
g = pg + x / exp(pg) - 1 g = pg + x / exp(pg) - 1.0
} }
return g return g
@ -194,7 +196,7 @@ fn log(a: float, b: float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(g - pg) > LOG_ACC { while absf(g - pg) > LOG_ACC {
pg = g pg = g
g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg)) g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg))
} }
@ -211,7 +213,7 @@ fn sin(x: float) -> float {
x = mod(x, 2.0*PI) x = mod(x, 2.0*PI)
if x > PI { if x > PI {
x = PI - x x = PI - x
f = -1 f = -1.0
} }
# compute sine with a taylor series mock function of sine (valid between -pi and +pi) # compute sine with a taylor series mock function of sine (valid between -pi and +pi)
@ -220,7 +222,7 @@ fn sin(x: float) -> float {
i := 1.0 i := 1.0
s := -1.0 s := -1.0
while i <= 19 { while i <= 19.0 {
i = i + 2.0 i = i + 2.0
l = s * l * x / i / (i-1.0) l = s * l * x / i / (i-1.0)
@ -235,13 +237,15 @@ fn sin(x: float) -> float {
# 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: number) number { fn cos(x: float) -> float {
# todo # todo
0.0
} }
# 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: number) number { fn tan(x: float) -> float {
# todo # todo
0.0
} }

11
tests/tuple.ang Normal file
View file

@ -0,0 +1,11 @@
assertEq((1, 2), (1, 2))
assertEq(typeof((1,)), typeof((1,)))
assertEq((1,), (1,))
fn neighbours(n: int) -> (int, int) {
(n-1, n+1)
}
assertEq(neighbours(2), (1, 3))

View file

@ -1,8 +1,15 @@
assertEq(type(1), "int") assertEq(typeof(1), "int")
assertEq(type("Hello"), "string") assertEq(typeof("Hello"), "string")
assertEq(type(true), "boolean") assertEq(typeof(true), "boolean")
# lists # lists
assertEq(type(["Hello", "world"]), "list[string]") assertEq(typeof(["Hello", "world"]), "[string]")
assertEq(type([0, 1]), "list[int]") assertEq(typeof([0, 1]), "[int]")
assertEq(typeof((0, 1)), "(int, int)")
type Vec2 = (int, int)
fn add(a: Vec2, b: Vec2) -> Vec2 {
(a[0] + b[0], a[1] + b[1])
}

3
wasm/Makefile Normal file
View file

@ -0,0 +1,3 @@
build:
GOOS=js GOARCH=wasm go build .