Compare commits
10 commits
5c336c7dec
...
575fd8e37a
| Author | SHA1 | Date | |
|---|---|---|---|
| 575fd8e37a | |||
| 91baf28fdf | |||
| 7cb2be8415 | |||
| 0bc8b2ef55 | |||
| dd7af341a3 | |||
| d54249cffe | |||
| 94b12f28ab | |||
| e03d18c7db | |||
| 7bb277045c | |||
| f41ada6770 |
33 changed files with 1740 additions and 1976 deletions
40
bad.ang
40
bad.ang
|
|
@ -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))
|
|
||||||
15
chars.ang
15
chars.ang
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
24
codegen.ang
24
codegen.ang
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
1421
core/compiler.go
1421
core/compiler.go
File diff suppressed because it is too large
Load diff
|
|
@ -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]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
134
core/nodes.go
134
core/nodes.go
|
|
@ -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
|
||||||
|
|
|
||||||
823
core/parser.go
823
core/parser.go
File diff suppressed because it is too large
Load diff
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
271
core/types.go
271
core/types.go
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
145
core/vm.go
145
core/vm.go
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
write(char(0x12) + char(0x85) + char(0x07))
|
|
||||||
11
era3.ang
11
era3.ang
|
|
@ -1,11 +0,0 @@
|
||||||
fn counter() -> (fn() -> int) {
|
|
||||||
i := 0
|
|
||||||
|
|
||||||
fn() -> int { i = i + 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
next := counter()
|
|
||||||
|
|
||||||
println(next())
|
|
||||||
println(next())
|
|
||||||
println(next())
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
func f(x) {
|
fn f(x) {
|
||||||
return x*x - 4
|
return x*x - 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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!!!!!!!!!!")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
import "math.ang"
|
import "math.ang"
|
||||||
|
|
||||||
write(sqrt(2))
|
println(sqrt(2.0))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import "lib/honning.ang"
|
|
||||||
|
|
||||||
write(_bell+_italic+"Hello "+_underline+"world "+_strike+"micheal"+_reset)
|
|
||||||
|
|
||||||
15
imp.ang
15
imp.ang
|
|
@ -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)))
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
50
lib/math.ang
50
lib/math.ang
|
|
@ -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
11
tests/tuple.ang
Normal 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))
|
||||||
|
|
@ -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
3
wasm/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
build:
|
||||||
|
GOOS=js GOARCH=wasm go build .
|
||||||
Loading…
Add table
Add a link
Reference in a new issue