Compare commits
No commits in common. "575fd8e37ad071d613fa512e8713dcab1a90293c" and "5c336c7decbd0536a5bc5d719dbc634f05bec8c5" have entirely different histories.
575fd8e37a
...
5c336c7dec
33 changed files with 1975 additions and 1739 deletions
40
bad.ang
Normal file
40
bad.ang
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
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
Normal file
15
chars.ang
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
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,8 +150,7 @@ func makeChunk(ctx *Context, fpath string, ignoreWarnings bool) (*core.Chunk, er
|
|||
if ctx.Debug {
|
||||
log.Println("Compiling parse tree")
|
||||
}
|
||||
|
||||
_, err = c.Compile(tree)
|
||||
err = c.Compile(tree)
|
||||
if err != nil {
|
||||
var e core.FormatedError
|
||||
if errors.As(err, &e) {
|
||||
|
|
@ -297,7 +296,7 @@ func (cmd *ReplCmd) Run(ctx *Context) error {
|
|||
}
|
||||
|
||||
c.SetSource(src)
|
||||
if _, err = c.Compile(prog); err != nil {
|
||||
if err = c.Compile(prog); err != nil {
|
||||
var e core.FormatedError
|
||||
if errors.As(err, &e) {
|
||||
log.Print(e.Format())
|
||||
|
|
|
|||
24
codegen.ang
Normal file
24
codegen.ang
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
1477
core/compiler.go
1477
core/compiler.go
File diff suppressed because it is too large
Load diff
|
|
@ -7,29 +7,24 @@ import (
|
|||
)
|
||||
|
||||
type Token struct {
|
||||
Type TokenKind
|
||||
Type TokenType
|
||||
Start Pos
|
||||
End Pos
|
||||
Line Pos
|
||||
Lexeme string
|
||||
}
|
||||
|
||||
func (t Token) Bounds() (Pos, Pos) {
|
||||
return t.Start, t.End
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
type TokenKind uint64
|
||||
type TokenType uint64
|
||||
|
||||
const (
|
||||
TokenPlus TokenKind = iota
|
||||
TokenPlus TokenType = iota
|
||||
TokenMinus
|
||||
TokenStar
|
||||
TokenSlash
|
||||
TokenPercent
|
||||
TokenBang
|
||||
TokenSemicolon
|
||||
|
||||
|
|
@ -56,10 +51,7 @@ const (
|
|||
TokenVar
|
||||
TokenIf
|
||||
TokenElse
|
||||
TokenInclude
|
||||
TokenType
|
||||
TokenFor
|
||||
TokenIn
|
||||
TokenImport
|
||||
|
||||
TokenComma
|
||||
TokenDot
|
||||
|
|
@ -85,7 +77,7 @@ const (
|
|||
TokenError
|
||||
)
|
||||
|
||||
func (t TokenKind) String() string {
|
||||
func (t TokenType) String() string {
|
||||
switch t {
|
||||
case TokenPlus:
|
||||
return "plus"
|
||||
|
|
@ -167,8 +159,8 @@ func (t TokenKind) String() string {
|
|||
return "open bracket"
|
||||
case TokenCloseBracket:
|
||||
return "close bracket"
|
||||
case TokenInclude:
|
||||
return "include"
|
||||
case TokenImport:
|
||||
return "import"
|
||||
case TokenColon:
|
||||
return "colon"
|
||||
case TokenPipe:
|
||||
|
|
@ -179,34 +171,11 @@ func (t TokenKind) String() string {
|
|||
return "arrow"
|
||||
case TokenNewLine:
|
||||
return "newline"
|
||||
case TokenType:
|
||||
return "type"
|
||||
case TokenFor:
|
||||
return "for"
|
||||
case TokenIn:
|
||||
return "in"
|
||||
}
|
||||
|
||||
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 {
|
||||
src []rune
|
||||
start Pos
|
||||
|
|
@ -269,8 +238,6 @@ func (l *Lexer) NextToken() (Token, error) {
|
|||
}
|
||||
|
||||
return l.makeToken(TokenSlash), nil
|
||||
case '%':
|
||||
return l.makeToken(TokenPercent), nil
|
||||
case '(':
|
||||
return l.makeToken(TokenOpenParenthesis), nil
|
||||
case ')':
|
||||
|
|
@ -373,12 +340,32 @@ func (l *Lexer) NextToken() (Token, error) {
|
|||
l.advance()
|
||||
}
|
||||
|
||||
lexeme := string(l.src[l.start:l.current])
|
||||
if k, ok := Keywords[lexeme]; ok {
|
||||
return l.makeToken(k), nil
|
||||
switch string(l.src[l.start:l.current]) {
|
||||
case "true":
|
||||
return l.makeToken(TokenTrue), 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() != '.' {
|
||||
if l.peek() == 'x' {
|
||||
l.advance()
|
||||
|
|
@ -413,7 +400,7 @@ func (l *Lexer) NextToken() (Token, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func NewToken(t TokenKind, start Pos, end Pos, line Pos, lexeme string) Token {
|
||||
func NewToken(t TokenType, start Pos, end Pos, line Pos, lexeme string) Token {
|
||||
return Token{
|
||||
Type: t,
|
||||
Start: start,
|
||||
|
|
@ -438,7 +425,7 @@ func (l *Lexer) Tokenize() ([]Token, error) {
|
|||
return tokens, err
|
||||
}
|
||||
|
||||
func (l *Lexer) makeToken(t TokenKind) Token {
|
||||
func (l *Lexer) makeToken(t TokenType) Token {
|
||||
return NewToken(t, l.start, l.current, l.line, string(l.src[l.start:l.current]))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,37 +6,37 @@ import (
|
|||
|
||||
type LexerTestData struct {
|
||||
source string
|
||||
expectedTokens []TokenKind
|
||||
expectedTokens []TokenType
|
||||
}
|
||||
|
||||
func GetLexerTestData() map[string]LexerTestData {
|
||||
return map[string]LexerTestData{
|
||||
"hello_world_string(1)": {
|
||||
"\"Hello world\"",
|
||||
[]TokenKind{TokenString, TokenEOF},
|
||||
[]TokenType{TokenString, TokenEOF},
|
||||
},
|
||||
"empty_string(1)": {
|
||||
"\"\"",
|
||||
[]TokenKind{TokenString, TokenEOF},
|
||||
[]TokenType{TokenString, TokenEOF},
|
||||
},
|
||||
"simple number(1)": {
|
||||
"1024",
|
||||
[]TokenKind{TokenInteger, TokenEOF},
|
||||
[]TokenType{TokenInteger, TokenEOF},
|
||||
},
|
||||
"simple_arithmetics(7)": {
|
||||
"1 + 23 / 4 * 3",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenInteger, TokenPlus, TokenInteger, TokenSlash,
|
||||
TokenInteger, TokenStar, TokenInteger, TokenEOF,
|
||||
},
|
||||
},
|
||||
"condition(3)": {
|
||||
"a <= 200",
|
||||
[]TokenKind{TokenName, TokenLessThanOrEqual, TokenInteger, TokenEOF},
|
||||
[]TokenType{TokenName, TokenLessThanOrEqual, TokenInteger, TokenEOF},
|
||||
},
|
||||
"if_statement(10)": {
|
||||
"if a >= 200 {\n write(\"Hello world!\")\n}",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenIf, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenOpenBrace, TokenNewLine,
|
||||
TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenNewLine,
|
||||
TokenCloseBrace, TokenEOF,
|
||||
|
|
@ -44,7 +44,7 @@ func GetLexerTestData() map[string]LexerTestData {
|
|||
},
|
||||
"if_else_statement(20)": {
|
||||
"if 23 * 2/3 > 32 {\n write(\"It is larger!\")\n} else {\n write(\"It is lower!\")\n}",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenIf, TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger, TokenGreaterThan, TokenInteger, 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": {
|
||||
"",
|
||||
[]TokenKind{TokenEOF},
|
||||
[]TokenType{TokenEOF},
|
||||
},
|
||||
"full_arithmetic_equality": {
|
||||
"a + 2 == 10 * 2 / 3",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenName, TokenPlus, TokenInteger, TokenEquals,
|
||||
TokenInteger, TokenStar, TokenInteger, TokenSlash, TokenInteger,
|
||||
TokenEOF,
|
||||
|
|
@ -65,11 +65,11 @@ func GetLexerTestData() map[string]LexerTestData {
|
|||
},
|
||||
"name": {
|
||||
"print",
|
||||
[]TokenKind{TokenName, TokenEOF},
|
||||
[]TokenType{TokenName, TokenEOF},
|
||||
},
|
||||
"bunch_of_parentheses": {
|
||||
"(((())))",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis, TokenOpenParenthesis,
|
||||
TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis, TokenCloseParenthesis,
|
||||
TokenEOF,
|
||||
|
|
@ -77,22 +77,22 @@ func GetLexerTestData() map[string]LexerTestData {
|
|||
},
|
||||
"space_before_string": {
|
||||
"\n \"\"",
|
||||
[]TokenKind{TokenNewLine, TokenString, TokenEOF},
|
||||
[]TokenType{TokenNewLine, TokenString, TokenEOF},
|
||||
},
|
||||
"write_call": {
|
||||
"write(\"Hello world\")",
|
||||
[]TokenKind{TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenEOF},
|
||||
[]TokenType{TokenName, TokenOpenParenthesis, TokenString, TokenCloseParenthesis, TokenEOF},
|
||||
},
|
||||
"complex_comparison": {
|
||||
"!(h__elo123 >= 1)",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenBang, TokenOpenParenthesis, TokenName, TokenGreaterThanOrEqual, TokenInteger, TokenCloseParenthesis,
|
||||
TokenEOF,
|
||||
},
|
||||
},
|
||||
"3assignments_1condition": {
|
||||
"a = 8 * 32\nb = a > 256\nc = a <= 256\n!b == c",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenName, TokenAssign, TokenInteger, TokenStar, TokenInteger, TokenNewLine,
|
||||
TokenName, TokenAssign, TokenName, TokenGreaterThan, TokenInteger, TokenNewLine,
|
||||
TokenName, TokenAssign, TokenName, TokenLessThanOrEqual, TokenInteger, TokenNewLine,
|
||||
|
|
@ -101,14 +101,14 @@ func GetLexerTestData() map[string]LexerTestData {
|
|||
},
|
||||
"function": {
|
||||
"fn sum(a, b) {\n return a + b\n}",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenFunc, TokenName, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
|
||||
TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace,
|
||||
},
|
||||
},
|
||||
"while_loop": {
|
||||
"while a < 5 {\n a = a + 1\n}",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenWhile, TokenName, TokenLessThan, TokenInteger, TokenOpenBrace, TokenNewLine,
|
||||
TokenName, TokenAssign, TokenName, TokenPlus, TokenInteger, TokenNewLine, TokenCloseBrace, TokenEOF,
|
||||
},
|
||||
|
|
@ -117,14 +117,14 @@ func GetLexerTestData() map[string]LexerTestData {
|
|||
"sum := fn(a, b) {\n" +
|
||||
" return a + b\n" +
|
||||
"}",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenName, TokenDeclare, TokenFunc, TokenOpenParenthesis, TokenName, TokenComma, TokenName, TokenCloseParenthesis,
|
||||
TokenOpenBrace, TokenNewLine, TokenReturn, TokenName, TokenPlus, TokenName, TokenNewLine, TokenCloseBrace,
|
||||
},
|
||||
},
|
||||
"list": {
|
||||
"data := [3, 1, 4, 1]",
|
||||
[]TokenKind{
|
||||
[]TokenType{
|
||||
TokenName, TokenDeclare, TokenOpenBracket, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenComma, TokenInteger, TokenCloseBracket,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
142
core/nodes.go
142
core/nodes.go
|
|
@ -16,7 +16,7 @@ type Node interface {
|
|||
Bounds() (Pos, Pos)
|
||||
}
|
||||
|
||||
type Bounded interface {
|
||||
type Boundary interface {
|
||||
Bounds() (Pos, Pos)
|
||||
}
|
||||
|
||||
|
|
@ -34,16 +34,12 @@ const (
|
|||
BlockNodeType
|
||||
ConditionalNodeType
|
||||
LoopNodeType
|
||||
ForNodeType
|
||||
AssignNodeType
|
||||
InvokeNodeType
|
||||
CallNodeType
|
||||
FunctionNodeType
|
||||
ReturnNodeType
|
||||
AccessNodeType
|
||||
AliasNodeType
|
||||
IndexNodeType
|
||||
IncludeNodeType
|
||||
BreakpointNodeType
|
||||
)
|
||||
|
||||
|
|
@ -72,7 +68,7 @@ func (n NodeType) String() string {
|
|||
case AssignNodeType:
|
||||
return "Assign"
|
||||
case InvokeNodeType:
|
||||
return "Invoke"
|
||||
return "Call"
|
||||
case FunctionNodeType:
|
||||
return "Function"
|
||||
case ReturnNodeType:
|
||||
|
|
@ -89,10 +85,6 @@ func (n NodeType) String() string {
|
|||
return "Unary"
|
||||
case CallNodeType:
|
||||
return "Call"
|
||||
case AliasNodeType:
|
||||
return "Alias"
|
||||
case IndexNodeType:
|
||||
return "Index"
|
||||
}
|
||||
return "Invalid Node Type"
|
||||
}
|
||||
|
|
@ -239,7 +231,7 @@ func (n TupleNode) Bounds() (Pos, Pos) {
|
|||
|
||||
type AccessNode struct {
|
||||
source Node
|
||||
property *Token
|
||||
property string
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
|
|
@ -250,7 +242,7 @@ func (n AccessNode) Type() NodeType {
|
|||
}
|
||||
|
||||
func (n AccessNode) String() string {
|
||||
return fmt.Sprintf("(%s from %s)", n.property.Lexeme, n.source)
|
||||
return fmt.Sprintf("(%s from %s)", n.property, n.source)
|
||||
}
|
||||
|
||||
func (n AccessNode) Bounds() (Pos, Pos) {
|
||||
|
|
@ -281,9 +273,9 @@ func (n BinaryOperation) String() string {
|
|||
return "less or equal"
|
||||
case BinaryGreaterEqual:
|
||||
return "greater or equal"
|
||||
case BinaryBooleanAnd:
|
||||
case BinaryAnd:
|
||||
return "and"
|
||||
case BinaryBooleanOr:
|
||||
case BinaryOr:
|
||||
return "or"
|
||||
}
|
||||
|
||||
|
|
@ -295,10 +287,9 @@ const (
|
|||
BinarySubtraction
|
||||
BinaryMultiplication
|
||||
BinaryDivision
|
||||
BinaryModulo
|
||||
|
||||
BinaryBooleanAnd
|
||||
BinaryBooleanOr
|
||||
BinaryAnd
|
||||
BinaryOr
|
||||
|
||||
// Comparison
|
||||
BinaryEquality
|
||||
|
|
@ -319,8 +310,6 @@ func (n BinaryOperation) Symbol() string {
|
|||
return "*"
|
||||
case BinaryDivision:
|
||||
return "/"
|
||||
case BinaryModulo:
|
||||
return "%"
|
||||
case BinaryEquality:
|
||||
return "=="
|
||||
case BinaryInequality:
|
||||
|
|
@ -333,9 +322,9 @@ func (n BinaryOperation) Symbol() string {
|
|||
return "<="
|
||||
case BinaryGreaterEqual:
|
||||
return ">="
|
||||
case BinaryBooleanAnd:
|
||||
case BinaryAnd:
|
||||
return "&&"
|
||||
case BinaryBooleanOr:
|
||||
case BinaryOr:
|
||||
return "||"
|
||||
}
|
||||
|
||||
|
|
@ -348,9 +337,8 @@ type BinaryNode struct {
|
|||
Left Node
|
||||
Right Node
|
||||
|
||||
operator *Token
|
||||
start Pos
|
||||
end Pos
|
||||
start Pos
|
||||
end Pos
|
||||
}
|
||||
|
||||
func (n BinaryNode) Type() NodeType {
|
||||
|
|
@ -398,9 +386,8 @@ type UnaryNode struct {
|
|||
UnaryOperation
|
||||
value Node
|
||||
|
||||
operator *Token
|
||||
start Pos
|
||||
end Pos
|
||||
start Pos
|
||||
end Pos
|
||||
}
|
||||
|
||||
func (n UnaryNode) Type() NodeType {
|
||||
|
|
@ -417,7 +404,7 @@ func (n UnaryNode) Bounds() (Pos, Pos) {
|
|||
|
||||
// BooleanNode boolean value
|
||||
type BooleanNode struct {
|
||||
Boolean bool
|
||||
value bool
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
|
|
@ -428,7 +415,7 @@ func (n BooleanNode) Type() NodeType {
|
|||
}
|
||||
|
||||
func (n BooleanNode) String() string {
|
||||
return strconv.FormatBool(n.Boolean)
|
||||
return strconv.FormatBool(n.value)
|
||||
}
|
||||
|
||||
func (n BooleanNode) Bounds() (Pos, Pos) {
|
||||
|
|
@ -506,7 +493,7 @@ func (n ConditionalNode) Bounds() (Pos, Pos) {
|
|||
return n.start, n.end
|
||||
}
|
||||
|
||||
// LoopNode While loops
|
||||
// LoopNode Loops (for/while)
|
||||
type LoopNode struct {
|
||||
condition Node
|
||||
do Node
|
||||
|
|
@ -527,28 +514,6 @@ func (n LoopNode) Bounds() (Pos, Pos) {
|
|||
return n.start, n.end
|
||||
}
|
||||
|
||||
// ForNode For loops
|
||||
type ForNode struct {
|
||||
counter Node
|
||||
iterator Node
|
||||
logic Node
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
}
|
||||
|
||||
func (n ForNode) Type() NodeType {
|
||||
return ForNodeType
|
||||
}
|
||||
|
||||
func (n ForNode) String() string {
|
||||
return fmt.Sprintf("for %s in %s; %s", n.counter, n.iterator, n.logic)
|
||||
}
|
||||
|
||||
func (n ForNode) Bounds() (Pos, Pos) {
|
||||
return n.start, n.end
|
||||
}
|
||||
|
||||
// AssignNode assignment
|
||||
type AssignNode struct {
|
||||
dest Node
|
||||
|
|
@ -595,7 +560,7 @@ func (n InvokeNode) Bounds() (Pos, Pos) {
|
|||
// CallNode call a function of a value
|
||||
type CallNode struct {
|
||||
source Node
|
||||
name *Token
|
||||
name Token
|
||||
args []Node
|
||||
|
||||
start Pos
|
||||
|
|
@ -642,18 +607,6 @@ func (n FunctionNode) Bounds() (Pos, Pos) {
|
|||
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
|
||||
type ReturnNode struct {
|
||||
value Node
|
||||
|
|
@ -674,65 +627,6 @@ func (n ReturnNode) Bounds() (Pos, Pos) {
|
|||
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 {
|
||||
start Pos
|
||||
end Pos
|
||||
|
|
|
|||
873
core/parser.go
873
core/parser.go
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,9 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -73,7 +74,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
2,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
|
|
@ -129,7 +129,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
"b",
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
|
|
@ -191,14 +190,12 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
1,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
&FloatNode{
|
||||
5,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
&BinaryNode{
|
||||
|
|
@ -217,13 +214,10 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
2,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
&BinaryNode{
|
||||
|
|
@ -236,10 +230,8 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
2,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
|
|
@ -272,7 +264,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
15,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
|
|
@ -308,7 +299,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
0,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
do: &BlockNode{
|
||||
|
|
@ -362,7 +352,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
0,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
do: &BlockNode{
|
||||
|
|
@ -470,7 +459,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
"b",
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
|
|
@ -542,7 +530,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
"b",
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
|
|
@ -578,7 +565,7 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
"a",
|
||||
0, 0,
|
||||
},
|
||||
&Token{TokenName, 0, 1, 0, "b"},
|
||||
"b",
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
|
|
@ -664,57 +651,6 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -781,10 +717,10 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
|||
NodeEquality(t, n1.(*BinaryNode).Right, n2.(*BinaryNode).Right)
|
||||
|
||||
case BooleanNodeType:
|
||||
if n1.(*BooleanNode).Boolean != n2.(*BooleanNode).Boolean {
|
||||
t.Errorf("Boolean node values don't match (%s and %s)", strconv.FormatBool(n1.(*BooleanNode).Boolean), strconv.FormatBool(n2.(*BooleanNode).Boolean))
|
||||
if n1.(*BooleanNode).value != n2.(*BooleanNode).value {
|
||||
t.Errorf("Boolean node values don't match (%s and %s)", strconv.FormatBool(n1.(*BooleanNode).value), strconv.FormatBool(n2.(*BooleanNode).value))
|
||||
} else {
|
||||
t.Logf("Boolean node values match (%s)", strconv.FormatBool(n1.(*BooleanNode).Boolean))
|
||||
t.Logf("Boolean node values match (%s)", strconv.FormatBool(n1.(*BooleanNode).value))
|
||||
}
|
||||
case BlockNodeType:
|
||||
if len(n1.(*BlockNode).statements) != len(n2.(*BlockNode).statements) {
|
||||
|
|
@ -854,7 +790,7 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
|||
}
|
||||
|
||||
for i, p := range m.parameters {
|
||||
if !n.parameters[i].Signature.Contains(p.Signature) {
|
||||
if !n.parameters[i].Signature.Matches(p.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 {
|
||||
t.Errorf("Function node parameter name %d does not match: %s and %s", i, p.Name, n.parameters[i].Name)
|
||||
|
|
@ -872,11 +808,10 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
|||
a1 := n1.(*AccessNode)
|
||||
a2 := n2.(*AccessNode)
|
||||
|
||||
// only care about lexeme; the rest is debug info
|
||||
if a1.property.Lexeme != a2.property.Lexeme {
|
||||
t.Errorf("Access node property does not match: .%s != .%s", a1.property.Lexeme, a2.property.Lexeme)
|
||||
if a1.property != a2.property {
|
||||
t.Errorf("Access node property does not match: .%s != .%s", a1.property, a2.property)
|
||||
} else {
|
||||
t.Logf("Access node property matches: .%s", a1.property.Lexeme)
|
||||
t.Logf("Access node property matches: .%s", a1.property)
|
||||
}
|
||||
|
||||
NodeEquality(t, a1.source, a2.source)
|
||||
|
|
@ -890,7 +825,7 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
|||
t.Logf("Both content types are yet to be determined")
|
||||
} else if l1.content != nil || l2.content != nil {
|
||||
t.Errorf("one is nil, one is not")
|
||||
} else if !l1.content.Contains(l2.content) {
|
||||
} else if !l1.content.Matches(l2.content) {
|
||||
t.Errorf("signature doesn't match")
|
||||
}
|
||||
|
||||
|
|
@ -899,24 +834,110 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
|||
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:
|
||||
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) {
|
||||
t.Logf("Getting test data")
|
||||
tokenData := GetTokenTestData()
|
||||
|
|
@ -939,31 +960,6 @@ 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) {
|
||||
tokenData := GetTokenTestData()
|
||||
|
||||
|
|
|
|||
283
core/types.go
283
core/types.go
|
|
@ -14,13 +14,11 @@ const (
|
|||
TypeBoolean
|
||||
TypeNil
|
||||
TypeList
|
||||
TypeTuple
|
||||
TypeObject
|
||||
TypeFunction
|
||||
TypeAny
|
||||
TypeComposite
|
||||
TypeInner
|
||||
TypeNamed
|
||||
)
|
||||
|
||||
func (t Type) String() string {
|
||||
|
|
@ -37,8 +35,6 @@ func (t Type) String() string {
|
|||
return "nil"
|
||||
case TypeList:
|
||||
return "list"
|
||||
case TypeTuple:
|
||||
return "tuple"
|
||||
case TypeObject:
|
||||
return "object"
|
||||
case TypeFunction:
|
||||
|
|
@ -72,7 +68,7 @@ func SignatureOf(v Value) TypeSignature {
|
|||
sig := SignatureOf(p)
|
||||
if contains == nil {
|
||||
contains = sig
|
||||
} else if !contains.Contains(sig) {
|
||||
} else if !contains.Matches(sig) {
|
||||
contains = &AnySignature{}
|
||||
break
|
||||
}
|
||||
|
|
@ -96,16 +92,6 @@ func SignatureOf(v Value) TypeSignature {
|
|||
}
|
||||
case *BuiltinFunctionValue:
|
||||
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))
|
||||
|
|
@ -114,12 +100,8 @@ func SignatureOf(v Value) TypeSignature {
|
|||
type TypeSignature interface {
|
||||
Type() Type
|
||||
|
||||
// Contains check if this type signature matches another.
|
||||
// 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
|
||||
// Matches check if this type signature matches another.
|
||||
Matches(TypeSignature) bool
|
||||
|
||||
// String create a human-readable string version of the value type.
|
||||
String() string
|
||||
|
|
@ -131,12 +113,12 @@ func (*NilSignature) Type() Type {
|
|||
return TypeNil
|
||||
}
|
||||
|
||||
func (s *NilSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeNil
|
||||
}
|
||||
func (s *NilSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *NilSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeNil
|
||||
return other.Type() == TypeAny || other.Type() == TypeNil
|
||||
}
|
||||
|
||||
func (*NilSignature) String() string {
|
||||
|
|
@ -149,16 +131,16 @@ func (*StringSignature) Type() Type {
|
|||
return TypeString
|
||||
}
|
||||
|
||||
func (s *StringSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeString
|
||||
}
|
||||
func (s *StringSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *StringSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeString
|
||||
return other.Type() == TypeAny || other.Type() == TypeString
|
||||
}
|
||||
|
||||
func (*StringSignature) String() string {
|
||||
return "str"
|
||||
return "string"
|
||||
}
|
||||
|
||||
type FloatSignature struct{}
|
||||
|
|
@ -167,12 +149,12 @@ func (*FloatSignature) Type() Type {
|
|||
return TypeFloat
|
||||
}
|
||||
|
||||
func (s *FloatSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeFloat
|
||||
}
|
||||
func (s *FloatSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *FloatSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeFloat
|
||||
return other.Type() == TypeAny || other.Type() == TypeFloat
|
||||
}
|
||||
|
||||
func (*FloatSignature) String() string {
|
||||
|
|
@ -185,12 +167,12 @@ func (*IntegerSignature) Type() Type {
|
|||
return TypeInteger
|
||||
}
|
||||
|
||||
func (s *IntegerSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeInteger
|
||||
}
|
||||
func (s *IntegerSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *IntegerSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeInteger
|
||||
return other.Type() == TypeAny || other.Type() == TypeInteger
|
||||
}
|
||||
|
||||
func (*IntegerSignature) String() string {
|
||||
|
|
@ -203,12 +185,12 @@ func (*BooleanSignature) Type() Type {
|
|||
return TypeBoolean
|
||||
}
|
||||
|
||||
func (s *BooleanSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeBoolean
|
||||
}
|
||||
func (s *BooleanSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *BooleanSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeBoolean
|
||||
return other.Type() == TypeAny || other.Type() == TypeBoolean
|
||||
}
|
||||
|
||||
func (*BooleanSignature) String() string {
|
||||
|
|
@ -223,75 +205,16 @@ func (*ListSignature) Type() Type {
|
|||
return TypeList
|
||||
}
|
||||
|
||||
func (s *ListSignature) Contains(other TypeSignature) bool {
|
||||
return other.Type() == TypeList && other.(*ListSignature).Contents.Contains(s.Contents)
|
||||
}
|
||||
func (s *ListSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
func (s *ListSignature) Equal(other TypeSignature) bool {
|
||||
return other.Type() == TypeList && other.(*ListSignature).Contents.Equal(s.Contents)
|
||||
return other.Type() == TypeAny || (other.Type() == TypeList && other.(*ListSignature).Contents.Matches(s.Contents))
|
||||
}
|
||||
|
||||
func (s *ListSignature) String() string {
|
||||
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()
|
||||
return fmt.Sprintf("list[%s]", s.Contents)
|
||||
}
|
||||
|
||||
type ObjectSignature struct {
|
||||
|
|
@ -302,13 +225,25 @@ func (*ObjectSignature) Type() Type {
|
|||
return TypeObject
|
||||
}
|
||||
|
||||
func (s *ObjectSignature) Contains(other TypeSignature) bool {
|
||||
func (s *ObjectSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
if other.Type() == TypeAny {
|
||||
return true
|
||||
}
|
||||
|
||||
if other.Type() != TypeObject {
|
||||
return false
|
||||
}
|
||||
|
||||
o := other.(*ObjectSignature)
|
||||
|
||||
if len(o.Members) != len(s.Members) {
|
||||
return false
|
||||
}
|
||||
|
||||
for name, member := range s.Members {
|
||||
v, ok := o.Members[name]
|
||||
|
||||
|
|
@ -316,29 +251,7 @@ func (s *ObjectSignature) Contains(other TypeSignature) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
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) {
|
||||
if !v.Matches(member) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -359,14 +272,22 @@ func (*FunctionSignature) Type() Type {
|
|||
return TypeFunction
|
||||
}
|
||||
|
||||
func (s *FunctionSignature) Contains(other TypeSignature) bool {
|
||||
func (s *FunctionSignature) Matches(other TypeSignature) bool {
|
||||
if other.Type() == TypeComposite {
|
||||
return other.Matches(s)
|
||||
}
|
||||
|
||||
if other.Type() == TypeAny {
|
||||
return true
|
||||
}
|
||||
|
||||
if other.Type() != TypeFunction {
|
||||
return false
|
||||
}
|
||||
|
||||
f := other.(*FunctionSignature)
|
||||
|
||||
if !s.Out.Contains(f.Out) {
|
||||
if !s.Out.Matches(f.Out) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +297,7 @@ func (s *FunctionSignature) Contains(other TypeSignature) bool {
|
|||
|
||||
for i, p := range s.In {
|
||||
v := f.In[i]
|
||||
if !p.Contains(v) {
|
||||
if !p.Matches(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -384,30 +305,10 @@ func (s *FunctionSignature) Contains(other TypeSignature) bool {
|
|||
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 {
|
||||
b := strings.Builder{}
|
||||
|
||||
b.WriteString("fn(")
|
||||
b.WriteString("func(")
|
||||
|
||||
for i, t := range s.In {
|
||||
if i > 0 {
|
||||
|
|
@ -418,7 +319,7 @@ func (s *FunctionSignature) String() string {
|
|||
|
||||
b.WriteString(")")
|
||||
if s.Out.Type() != TypeNil {
|
||||
b.WriteString(" -> ")
|
||||
b.WriteString(" ")
|
||||
b.WriteString(s.Out.String())
|
||||
}
|
||||
|
||||
|
|
@ -431,14 +332,10 @@ func (*AnySignature) Type() Type {
|
|||
return TypeAny
|
||||
}
|
||||
|
||||
func (*AnySignature) Contains(_ TypeSignature) bool {
|
||||
func (*AnySignature) Matches(_ TypeSignature) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *AnySignature) Equal(t TypeSignature) bool {
|
||||
return t.Type() == TypeAny
|
||||
}
|
||||
|
||||
func (*AnySignature) String() string {
|
||||
return "any"
|
||||
}
|
||||
|
|
@ -452,72 +349,24 @@ func (*CompositeSignature) Type() Type {
|
|||
return TypeComposite
|
||||
}
|
||||
|
||||
func (s *CompositeSignature) Contains(other TypeSignature) bool {
|
||||
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) Matches(other TypeSignature) bool {
|
||||
return s.A.Matches(other) || s.B.Matches(other)
|
||||
}
|
||||
|
||||
func (s *CompositeSignature) String() string {
|
||||
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{}
|
||||
|
||||
func (*InnerSignature) Type() Type {
|
||||
return TypeInner
|
||||
}
|
||||
|
||||
func (*InnerSignature) Contains(_ TypeSignature) bool {
|
||||
func (*InnerSignature) Matches(_ TypeSignature) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *InnerSignature) Equal(t TypeSignature) bool {
|
||||
return t.Type() == TypeInner
|
||||
}
|
||||
|
||||
func (*InnerSignature) String() string {
|
||||
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,7 +6,6 @@ import (
|
|||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ValueType int
|
||||
|
|
@ -18,7 +17,6 @@ const (
|
|||
IntegerValueType
|
||||
StringValueType
|
||||
ListValueType
|
||||
TupleValueType
|
||||
ObjectValueType
|
||||
FunctionValueType
|
||||
BuiltinFunctionValueType
|
||||
|
|
@ -41,8 +39,6 @@ func (v ValueType) String() string {
|
|||
return "string"
|
||||
case ListValueType:
|
||||
return "list"
|
||||
case TupleValueType:
|
||||
return "tuple"
|
||||
case FunctionValueType:
|
||||
return "function"
|
||||
case BuiltinFunctionValueType:
|
||||
|
|
@ -223,8 +219,8 @@ func (v *ObjectValue) Equals(other Value) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
var ObjectPrototype = map[string]*BuiltinFunctionValue{
|
||||
"set": {
|
||||
var ObjectPrototype = map[string]Value{
|
||||
"set": &BuiltinFunctionValue{
|
||||
"set",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&StringSignature{}, &ListSignature{}},
|
||||
|
|
@ -282,12 +278,7 @@ func (v *FloatValue) Type() ValueType {
|
|||
}
|
||||
|
||||
func (v *FloatValue) String() string {
|
||||
s := strconv.FormatFloat(v.Number, 'g', -1, FloatSize)
|
||||
if strings.Index(s, ".") == -1 {
|
||||
s += ".0"
|
||||
}
|
||||
|
||||
return s
|
||||
return strconv.FormatFloat(v.Number, 'g', -1, FloatSize)
|
||||
}
|
||||
|
||||
func (v *FloatValue) DebugString() string {
|
||||
|
|
@ -606,88 +597,6 @@ 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 {
|
||||
Name string
|
||||
Params []FunctionParameter
|
||||
|
|
@ -742,7 +651,7 @@ func (v *BuiltinFunctionValue) Type() ValueType {
|
|||
}
|
||||
|
||||
func (v *BuiltinFunctionValue) String() string {
|
||||
return fmt.Sprintf("<function builtin name=%s>", v.Name)
|
||||
return fmt.Sprintf("<function name=%s builtin>", v.Name)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if !n.Signature.Contains(m.Signature) {
|
||||
if !n.Signature.Matches(m.Signature) {
|
||||
t.Errorf("builtin function parameter count mismatch: got %v, want %v", n, m)
|
||||
}
|
||||
|
||||
|
|
@ -96,19 +96,6 @@ func CompareValues(t *testing.T, got Value, want Value) {
|
|||
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:
|
||||
panic("unimplemented comparison")
|
||||
}
|
||||
|
|
|
|||
147
core/vm.go
147
core/vm.go
|
|
@ -41,8 +41,6 @@ const (
|
|||
InstructionMulInt
|
||||
// InstructionDivInt pop two ints and divide the second by the first
|
||||
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
|
||||
|
||||
|
|
@ -101,8 +99,8 @@ const (
|
|||
|
||||
// InstructionStringConversion Take the top value on the stack and convert it to a string
|
||||
InstructionStringConversion
|
||||
// InstructionConcatStrings Add two strings together, with the second value on the stack as left and the top as right
|
||||
InstructionConcatStrings
|
||||
// InstructionStringConcatenation Add two strings together, with the second value on the stack as left and the top as right
|
||||
InstructionStringConcatenation
|
||||
|
||||
// InstructionSwap swap the two top items on the stack (1, 2 -> 2, 1)
|
||||
InstructionSwap
|
||||
|
|
@ -123,33 +121,17 @@ const (
|
|||
// InstructionNil Push a nil literal to the stack
|
||||
InstructionNil
|
||||
|
||||
// InstructionNewList Push a new (empty) list to the stack
|
||||
InstructionNewList
|
||||
// InstructionAppend Append to a list. stack: (... > list > item) => (... > list)
|
||||
InstructionAppend
|
||||
// InstructionFormList Form items on the stack into a list. The 2 bytes after the instructions are the amount of
|
||||
// items to include) The order is reversed compared to on the stack; the top value on the stack is the last in the
|
||||
// list.
|
||||
// items to include minus one. (value of 0 => 1 item, value of 1 => 2 items, etc.) The order is reversed compared
|
||||
// to on the stack; the top value on the stack is the last in the list.
|
||||
InstructionFormList
|
||||
// InstructionConcatLists concatenate lists, producing a new list with the values of both lists. Pops two lists.
|
||||
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
|
||||
)
|
||||
|
|
@ -234,7 +216,7 @@ func (b Bytecode) String() string {
|
|||
return "ASCEND"
|
||||
case InstructionStringConversion:
|
||||
return "STRING_CONVERSION"
|
||||
case InstructionConcatStrings:
|
||||
case InstructionStringConcatenation:
|
||||
return "STRING_CONCATENATION"
|
||||
case InstructionSwap:
|
||||
return "SWAP"
|
||||
|
|
@ -246,6 +228,8 @@ func (b Bytecode) String() string {
|
|||
return "FORM_LIST"
|
||||
case InstructionBreakpoint:
|
||||
return "BREAKPOINT"
|
||||
case InstructionNewList:
|
||||
return "NEW_LIST"
|
||||
case InstructionAppend:
|
||||
return "APPEND"
|
||||
case InstructionAccessProperty:
|
||||
|
|
@ -254,14 +238,6 @@ func (b Bytecode) String() string {
|
|||
return "CONCAT_LISTS"
|
||||
case InstructionDuplicate:
|
||||
return "DUPLICATE"
|
||||
case InstructionFormTuple:
|
||||
return "FORM_TUPLE"
|
||||
case InstructionIndexList:
|
||||
return "INDEX_LIST"
|
||||
case InstructionIndexTuple:
|
||||
return "INDEX_TUPLE"
|
||||
case InstructionDestructureTuple:
|
||||
return "DESTRUCTURE_TUPLE"
|
||||
}
|
||||
return "UNDEFINED"
|
||||
}
|
||||
|
|
@ -271,7 +247,7 @@ type Chunk struct {
|
|||
Constants []Value
|
||||
}
|
||||
|
||||
func (c *Chunk) String() string {
|
||||
func (c Chunk) String() string {
|
||||
b := strings.Builder{}
|
||||
|
||||
b.WriteString("=v= chunk =v=\n")
|
||||
|
|
@ -344,7 +320,7 @@ func RegisterGOBTypes() {
|
|||
|
||||
}
|
||||
|
||||
func (c *Chunk) Serialize() []byte {
|
||||
func (c Chunk) Serialize() []byte {
|
||||
b := bytes.Buffer{}
|
||||
|
||||
e := gob.NewEncoder(&b)
|
||||
|
|
@ -573,13 +549,7 @@ var DefaultGlobals = map[string]Value{
|
|||
"int": &BuiltinFunctionValue{
|
||||
"int",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{
|
||||
quickComposite(
|
||||
&IntegerSignature{},
|
||||
&FloatSignature{},
|
||||
&StringSignature{},
|
||||
),
|
||||
},
|
||||
[]TypeSignature{&AnySignature{}},
|
||||
&CompositeSignature{
|
||||
&IntegerSignature{},
|
||||
&NilSignature{},
|
||||
|
|
@ -600,7 +570,7 @@ var DefaultGlobals = map[string]Value{
|
|||
|
||||
return &IntegerValue{n}, nil
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer (undefined)", v))
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v))
|
||||
}
|
||||
},
|
||||
nil,
|
||||
|
|
@ -609,38 +579,35 @@ var DefaultGlobals = map[string]Value{
|
|||
"float": &BuiltinFunctionValue{
|
||||
"float",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{
|
||||
quickComposite(
|
||||
&FloatSignature{},
|
||||
&IntegerSignature{},
|
||||
&StringSignature{},
|
||||
),
|
||||
[]TypeSignature{&AnySignature{}},
|
||||
&CompositeSignature{
|
||||
&FloatSignature{},
|
||||
&NilSignature{},
|
||||
},
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, _ Value, args []Value) (Value, error) {
|
||||
switch v := args[0].(type) {
|
||||
case *IntegerValue:
|
||||
n, _ := v.Number.Float64()
|
||||
return &FloatValue{n}, nil
|
||||
return &FloatValue{n}, nil // this might need to clone the value instead
|
||||
case *FloatValue:
|
||||
return v.Clone(), nil
|
||||
return &FloatValue{v.Number}, nil
|
||||
case *StringValue:
|
||||
num, err := strconv.ParseFloat(v.Text, FloatSize)
|
||||
if err != nil {
|
||||
return &FloatValue{}, nil
|
||||
return &NilValue{}, nil
|
||||
}
|
||||
|
||||
return &FloatValue{num}, nil
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer (undefined)", v))
|
||||
return nil, errors.New(fmt.Sprintf("%s cannot become an integer", v))
|
||||
}
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
"typeof": &BuiltinFunctionValue{
|
||||
Name: "typeof",
|
||||
"type": &BuiltinFunctionValue{
|
||||
Name: "type",
|
||||
Signature: &FunctionSignature{
|
||||
In: []TypeSignature{&AnySignature{}},
|
||||
Out: &StringSignature{},
|
||||
|
|
@ -693,12 +660,12 @@ var DefaultGlobals = map[string]Value{
|
|||
"roundd": &BuiltinFunctionValue{
|
||||
"roundd",
|
||||
&FunctionSignature{
|
||||
[]TypeSignature{&FloatSignature{}, &IntegerSignature{}},
|
||||
[]TypeSignature{&FloatSignature{}, &FloatSignature{}},
|
||||
&FloatSignature{},
|
||||
},
|
||||
func(vm *VM, this Value, args []Value) (Value, error) {
|
||||
x := args[0].(*FloatValue).Number
|
||||
decimals, _ := args[1].(*IntegerValue).Number.Float64()
|
||||
decimals := args[1].(*FloatValue).Number
|
||||
multiplier := math.Pow(10, decimals)
|
||||
return &FloatValue{math.Round(x*multiplier) / multiplier}, nil
|
||||
},
|
||||
|
|
@ -812,12 +779,6 @@ func (vm *VM) Next() bool {
|
|||
|
||||
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:
|
||||
v := vm.Stack.Pop().(*IntegerValue).Number
|
||||
|
||||
|
|
@ -1002,6 +963,9 @@ func (vm *VM) Next() bool {
|
|||
items,
|
||||
})
|
||||
|
||||
case InstructionNewList:
|
||||
vm.Stack.Push(&ListValue{[]Value{}})
|
||||
|
||||
case InstructionAppend:
|
||||
value := vm.Stack.Pop()
|
||||
list := vm.Stack.Pop().(*ListValue)
|
||||
|
|
@ -1016,23 +980,6 @@ func (vm *VM) Next() bool {
|
|||
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:
|
||||
vm.descend()
|
||||
|
||||
|
|
@ -1043,7 +990,7 @@ func (vm *VM) Next() bool {
|
|||
v := vm.Stack.Pop()
|
||||
vm.Stack.Push(&StringValue{v.String()})
|
||||
|
||||
case InstructionConcatStrings:
|
||||
case InstructionStringConcatenation:
|
||||
r := vm.Stack.Pop().(*StringValue).Text
|
||||
l := vm.Stack.Pop().(*StringValue).Text
|
||||
|
||||
|
|
@ -1076,42 +1023,6 @@ func (vm *VM) Next() bool {
|
|||
|
||||
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:
|
||||
/*
|
||||
// I'm keeping this
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package core
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -616,28 +615,6 @@ func GetExecutionTestData() map[string]struct {
|
|||
},
|
||||
[]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{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
2
emoji.ang
Normal file
2
emoji.ang
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
write(char(0x12) + char(0x85) + char(0x07))
|
||||
11
era3.ang
Normal file
11
era3.ang
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fn counter() -> (fn() -> int) {
|
||||
i := 0
|
||||
|
||||
fn() -> int { i = i + 1 }
|
||||
}
|
||||
|
||||
next := counter()
|
||||
|
||||
println(next())
|
||||
println(next())
|
||||
println(next())
|
||||
|
|
@ -1,20 +1,19 @@
|
|||
|
||||
println("Bonjour à tout!")
|
||||
write("Bonjour à tout!");
|
||||
|
||||
if 1 == 2 {
|
||||
# unreachable
|
||||
println("Wooot?? One does equal 2????")
|
||||
} else {
|
||||
println("Hooray! One does not equal 2!")
|
||||
write("Hooray! One does not equal 2!");
|
||||
}
|
||||
|
||||
for n in 0..10 {
|
||||
println("Run number " + str(n))
|
||||
for (var n = 1; n < 10; n = n + 1) {
|
||||
write("Run number " + str(n));
|
||||
}
|
||||
|
||||
a := 2
|
||||
var a = 2;
|
||||
|
||||
println(3 * a*a + 10 / 3)
|
||||
write(3 * a*a + 10 / 3);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
|
||||
# calculate fibonacci numbers with a loop
|
||||
|
||||
fn range(from: int, to: int) -> (fn() -> (int, bool)) {
|
||||
i := from - 1
|
||||
end := to - 1
|
||||
x := 0
|
||||
|
||||
fn() -> (int, bool) {
|
||||
if i < end {
|
||||
(i = i+1, true)
|
||||
} else {
|
||||
(-1, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
n := 1
|
||||
p := 1
|
||||
|
||||
(a, b) := (0, 1)
|
||||
for _ in range(0, 100) {
|
||||
(a, b) = (a + b, a)
|
||||
println(a)
|
||||
while x < 100 {
|
||||
f := n + p
|
||||
|
||||
p = n
|
||||
n = f
|
||||
|
||||
write(f)
|
||||
x = x + 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
fn sum(a: int, b: int) -> int {
|
||||
a + b
|
||||
func sum(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
println(sum(1, 2))
|
||||
write(sum(1, 2))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
fn f(x) {
|
||||
func f(x) {
|
||||
return x*x - 4
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
|
||||
println("Hello world!")
|
||||
write("Hello world!")
|
||||
|
||||
a := 1 + 2
|
||||
println(a)
|
||||
|
||||
write(a)
|
||||
|
||||
|
||||
if a > 2 {
|
||||
println("Hooray!! a is greater than 2!!!!")
|
||||
write("Hooray!! a is greater than 2!!!!")
|
||||
} else {
|
||||
println("oh nooo!!! a is less than or equal to 2!!!!!!!!!!")
|
||||
write("oh nooo!!! a is less than or equal to 2!!!!!!!!!!")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
import "math.ang"
|
||||
|
||||
println(sqrt(2.0))
|
||||
write(sqrt(2))
|
||||
|
|
|
|||
|
|
@ -1,47 +1,51 @@
|
|||
|
||||
# Empty list
|
||||
println([])
|
||||
write([])
|
||||
|
||||
# List with items
|
||||
println([3, 1, 4, 1, 5, 9, 2, 6, 5])
|
||||
write([3, 1, 4, 1, 5, 9, 2, 6, 5])
|
||||
|
||||
# List with items of different types
|
||||
println(["", "私はかっこいいです。", true, nil, nil, 1, 2])
|
||||
write(["", "私はかっこいいです。", true, nil, nil, 1, 2])
|
||||
|
||||
a := []
|
||||
|
||||
a = a + [1]
|
||||
a = a + [2]
|
||||
a = a.append(1)
|
||||
a = a.append(2)
|
||||
|
||||
println(a)
|
||||
write(a)
|
||||
|
||||
|
||||
list := []
|
||||
|
||||
n := 0
|
||||
x := 0
|
||||
for n in 0..100 {
|
||||
while n < 100 {
|
||||
x = x + 2*n + 1
|
||||
|
||||
list = list + [x]
|
||||
list = list.append(x)
|
||||
n = n + 1
|
||||
}
|
||||
|
||||
println(list)
|
||||
println(list.map(func(a) {
|
||||
write(list)
|
||||
write(list.map(func(a) {
|
||||
return a - 1
|
||||
}))
|
||||
println(list.length())
|
||||
println(list.at(69))
|
||||
write(list.length())
|
||||
write(list.at(69))
|
||||
|
||||
other := []
|
||||
|
||||
for a in 0..=10 {
|
||||
a := 1
|
||||
while a <= 10 {
|
||||
other = other.append(a)
|
||||
a = a + 1
|
||||
}
|
||||
|
||||
sum := other.reduce(func(tot, x) {
|
||||
return tot + x
|
||||
}, 0)
|
||||
|
||||
println(sum)
|
||||
write(sum)
|
||||
|
||||
assert(sum == a*(a-1)/2)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ tot = tot * 6.0
|
|||
# get the absolute value of a number
|
||||
fn abs(x: float) -> float {
|
||||
if x < 0.0 {
|
||||
-x
|
||||
} else {
|
||||
x
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
# calculate an approximation of the square root of tot using
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import "math.ang"
|
||||
|
||||
fn r_x(t: float) -> float {
|
||||
return 8.0*(exp(-t) - t)
|
||||
func r_x(t) {
|
||||
return 8*(exp(-t) - t)
|
||||
}
|
||||
|
||||
fn r_y(t: float) -> float {
|
||||
return 5.0*(exp(-t) - t)
|
||||
func r_y(t) {
|
||||
return 5*(exp(-t) - t)
|
||||
}
|
||||
|
||||
fn r(t: float) -> (float, float) {
|
||||
return (r_x(t), r_y(t))
|
||||
func r(t) {
|
||||
return format("(%s, %s)", [r_x(t), r_y(t)])
|
||||
}
|
||||
|
||||
println(r(1.0))
|
||||
write(r(1))
|
||||
write()
|
||||
|
|
|
|||
4
fails.ang
Normal file
4
fails.ang
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import "lib/honning.ang"
|
||||
|
||||
write(_bell+_italic+"Hello "+_underline+"world "+_strike+"micheal"+_reset)
|
||||
|
||||
15
imp.ang
Normal file
15
imp.ang
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
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 (l: list) map(list: [any], f: fn(any) -> any) -> [any] {
|
||||
fn map(list: [any], f: fn(any) -> any) -> [any] {
|
||||
out := []
|
||||
|
||||
i := 0
|
||||
|
|
|
|||
50
lib/math.ang
50
lib/math.ang
|
|
@ -9,7 +9,7 @@ E := 2.718281828459045235360287471352
|
|||
# returned value is x.
|
||||
fn absf(x: float) -> float {
|
||||
# if the number is negative
|
||||
if x < 0.0 {
|
||||
if x < 0 {
|
||||
# negate it so it's positive
|
||||
return -x
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ fn absi(n: int) -> int {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ fn newtons(f: fn(float) -> float) -> float {
|
|||
pg := 0.0
|
||||
g := 1.0
|
||||
|
||||
while absf(g - pg) > NEWTONS_ACC {
|
||||
while abs(g - pg) > NEWTONS_ACC {
|
||||
pg = g
|
||||
g = pg - f(pg) / derive(f, pg)
|
||||
}
|
||||
|
|
@ -53,14 +53,12 @@ fn sqrt(x: float) -> float {
|
|||
ng := x
|
||||
g := 1.0
|
||||
|
||||
while absf(g - ng) > MAX_SQRT_DX {
|
||||
while abs(g - ng) > MAX_SQRT_DX {
|
||||
g = ng
|
||||
|
||||
# create new guess
|
||||
ng = (g + x / g) / 2.0
|
||||
ng = (g + x / g) / 2
|
||||
}
|
||||
|
||||
g
|
||||
}
|
||||
|
||||
# floor(x)
|
||||
|
|
@ -84,7 +82,7 @@ fn round(x: float) -> float {
|
|||
f := floor(x)
|
||||
|
||||
if x - f > 0.5 {
|
||||
return f + 1.0
|
||||
return f + 1
|
||||
}
|
||||
|
||||
return f
|
||||
|
|
@ -95,16 +93,16 @@ fn round(x: float) -> float {
|
|||
# n: number; the number to divide by
|
||||
# Return the rest from a division of x by n.
|
||||
fn mod(x: float, n: float) -> float {
|
||||
if x == 0.0 {
|
||||
return 0.0
|
||||
if x == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if x < 0.0 {
|
||||
while x + n <= 0.0 {
|
||||
if x < 0 {
|
||||
while x + n <= 0 {
|
||||
x = x + n
|
||||
}
|
||||
} else {
|
||||
while x - n >= 0.0 {
|
||||
while x - n >= 0 {
|
||||
x = x - n
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +123,7 @@ fn sm_exp(x: float) -> float {
|
|||
x_pow := x
|
||||
f := 1.0
|
||||
|
||||
while absf(tot - p_tot) > SM_EXP_ACC {
|
||||
while abs(tot - p_tot) > SM_EXP_ACC {
|
||||
p_tot = tot
|
||||
t := x_pow / f
|
||||
tot = tot + t
|
||||
|
|
@ -141,18 +139,18 @@ fn sm_exp(x: float) -> float {
|
|||
# x: number; any number
|
||||
# Get an approximate value of e raised to the power of x.
|
||||
fn exp(x: float) -> float {
|
||||
n := absf(x)
|
||||
n := abs(x)
|
||||
tot := 1.0
|
||||
while n >= 1.0 {
|
||||
while n >= 1 {
|
||||
tot = tot * E
|
||||
n = n - 1.0
|
||||
n = n - 1
|
||||
}
|
||||
|
||||
if n > 0.0 {
|
||||
tot = tot * sm_exp(n)
|
||||
}
|
||||
|
||||
if x < 0.0 {
|
||||
if x < 0 {
|
||||
1.0/tot
|
||||
} else {
|
||||
tot
|
||||
|
|
@ -168,9 +166,9 @@ fn ln(x: float) -> float {
|
|||
pg := 0.0
|
||||
g := 1.0
|
||||
|
||||
while absf(pg - g) > LN_ACC {
|
||||
while abs(pg - g) > LN_ACC {
|
||||
pg = g
|
||||
g = pg + x / exp(pg) - 1.0
|
||||
g = pg + x / exp(pg) - 1
|
||||
}
|
||||
|
||||
return g
|
||||
|
|
@ -196,7 +194,7 @@ fn log(a: float, b: float) -> float {
|
|||
pg := 0.0
|
||||
g := 1.0
|
||||
|
||||
while absf(g - pg) > LOG_ACC {
|
||||
while abs(g - pg) > LOG_ACC {
|
||||
pg = g
|
||||
g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg))
|
||||
}
|
||||
|
|
@ -213,7 +211,7 @@ fn sin(x: float) -> float {
|
|||
x = mod(x, 2.0*PI)
|
||||
if x > PI {
|
||||
x = PI - x
|
||||
f = -1.0
|
||||
f = -1
|
||||
}
|
||||
|
||||
# compute sine with a taylor series mock function of sine (valid between -pi and +pi)
|
||||
|
|
@ -222,7 +220,7 @@ fn sin(x: float) -> float {
|
|||
i := 1.0
|
||||
s := -1.0
|
||||
|
||||
while i <= 19.0 {
|
||||
while i <= 19 {
|
||||
i = i + 2.0
|
||||
l = s * l * x / i / (i-1.0)
|
||||
|
||||
|
|
@ -237,15 +235,13 @@ fn sin(x: float) -> float {
|
|||
# cos(x)
|
||||
# x: number; an angle in radians
|
||||
# Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
||||
fn cos(x: float) -> float {
|
||||
func cos(x: number) number {
|
||||
# todo
|
||||
0.0
|
||||
}
|
||||
|
||||
# tan(x)
|
||||
# x: number; an angle in radians
|
||||
# Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent
|
||||
fn tan(x: float) -> float {
|
||||
func tan(x: number) number {
|
||||
# todo
|
||||
0.0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
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,15 +1,8 @@
|
|||
|
||||
assertEq(typeof(1), "int")
|
||||
assertEq(typeof("Hello"), "string")
|
||||
assertEq(typeof(true), "boolean")
|
||||
assertEq(type(1), "int")
|
||||
assertEq(type("Hello"), "string")
|
||||
assertEq(type(true), "boolean")
|
||||
|
||||
# lists
|
||||
assertEq(typeof(["Hello", "world"]), "[string]")
|
||||
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])
|
||||
}
|
||||
assertEq(type(["Hello", "world"]), "list[string]")
|
||||
assertEq(type([0, 1]), "list[int]")
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
build:
|
||||
GOOS=js GOARCH=wasm go build .
|
||||
Loading…
Add table
Add a link
Reference in a new issue