fix type-to-string conv. + fix binary type check + add modulo + rework import (now include)
Some checks failed
/ test (push) Failing after 41s
Some checks failed
/ test (push) Failing after 41s
This commit is contained in:
parent
91baf28fdf
commit
575fd8e37a
7 changed files with 131 additions and 91 deletions
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -173,28 +173,10 @@ func (c *Compiler) addConstant(value Value) {
|
||||||
c.add(Bytecode(len(chunk.Constants) - 1))
|
c.add(Bytecode(len(chunk.Constants) - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) Compile(p *Program) error {
|
func (c *Compiler) Compile(p *Program) (TypeSignature, error) {
|
||||||
c.fileStack.Push(p.Path)
|
c.fileStack.Push(p.Path)
|
||||||
|
|
||||||
for _, i := range p.Imports {
|
return c.compile(p.Block)
|
||||||
if err := c.resolveImport(i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, s := range p.Block.statements {
|
|
||||||
if _, err := c.compile(s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != len(p.Block.statements)-1 {
|
|
||||||
c.add(InstructionPop)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.fileStack.Pop()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func EscapeString(in string) string {
|
func EscapeString(in string) string {
|
||||||
|
|
@ -682,6 +664,9 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
|
||||||
|
|
||||||
return sig, nil
|
return sig, nil
|
||||||
|
|
||||||
|
case IncludeNodeType:
|
||||||
|
return c.compileInclude(tree.(*IncludeNode))
|
||||||
|
|
||||||
case AccessNodeType:
|
case AccessNodeType:
|
||||||
n := tree.(*AccessNode)
|
n := tree.(*AccessNode)
|
||||||
ps, err := c.compile(n.source)
|
ps, err := c.compile(n.source)
|
||||||
|
|
@ -837,20 +822,33 @@ func (c *Compiler) compileBinary(binary *BinaryNode) (TypeSignature, error) {
|
||||||
case BinarySubtraction:
|
case BinarySubtraction:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionSubFloat)
|
c.add(InstructionSubFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionSubInt)
|
c.add(InstructionSubInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot subtract %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
case BinaryMultiplication:
|
case BinaryMultiplication:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionMulFloat)
|
c.add(InstructionMulFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionMulInt)
|
c.add(InstructionMulInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot multiply %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
case BinaryDivision:
|
case BinaryDivision:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionDivFloat)
|
c.add(InstructionDivFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionDivInt)
|
c.add(InstructionDivInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot divide %s", tl), binary.operator)
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryModulo:
|
||||||
|
if tl.Type() == TypeInteger {
|
||||||
|
c.add(InstructionModInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot compute modulo of %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
case BinaryEquality:
|
case BinaryEquality:
|
||||||
c.add(InstructionEquals)
|
c.add(InstructionEquals)
|
||||||
|
|
@ -862,36 +860,52 @@ func (c *Compiler) compileBinary(binary *BinaryNode) (TypeSignature, error) {
|
||||||
case BinaryLess:
|
case BinaryLess:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionLessFloat)
|
c.add(InstructionLessFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionLessInt)
|
c.add(InstructionLessInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot compare ordering of %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
case BinaryGreater:
|
case BinaryGreater:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionGreaterFloat)
|
c.add(InstructionGreaterFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionGreaterInt)
|
c.add(InstructionGreaterInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot compare ordering of %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
case BinaryLessEqual:
|
case BinaryLessEqual:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionLessOrEqualFloat)
|
c.add(InstructionLessOrEqualFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionLessOrEqualInt)
|
c.add(InstructionLessOrEqualInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot compare ordering of %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
case BinaryGreaterEqual:
|
case BinaryGreaterEqual:
|
||||||
if tl.Type() == TypeFloat {
|
if tl.Type() == TypeFloat {
|
||||||
c.add(InstructionGreaterOrEqualFloat)
|
c.add(InstructionGreaterOrEqualFloat)
|
||||||
} else {
|
} else if tl.Type() == TypeInteger {
|
||||||
c.add(InstructionGreaterOrEqualInt)
|
c.add(InstructionGreaterOrEqualInt)
|
||||||
|
} else {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot compare ordering of %s", tl), binary.operator)
|
||||||
}
|
}
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
|
|
||||||
case BinaryBooleanAnd:
|
case BinaryBooleanAnd:
|
||||||
|
if tl.Type() != TypeBoolean {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot boolean-and of non-boolean %s", tl), binary.operator)
|
||||||
|
}
|
||||||
|
|
||||||
c.add(InstructionAnd)
|
c.add(InstructionAnd)
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
case BinaryBooleanOr:
|
case BinaryBooleanOr:
|
||||||
|
if tl.Type() != TypeBoolean {
|
||||||
|
return nil, c.error(fmt.Sprintf("cannot boolean-or of non-boolean %s", tl), binary.operator)
|
||||||
|
}
|
||||||
|
|
||||||
c.add(InstructionOr)
|
c.add(InstructionOr)
|
||||||
res = &BooleanSignature{}
|
res = &BooleanSignature{}
|
||||||
}
|
}
|
||||||
|
|
@ -1071,49 +1085,50 @@ func (c *Compiler) warn(msg string, causer Node) {
|
||||||
c.Warnings = append(c.Warnings, c.error(msg, causer))
|
c.Warnings = append(c.Warnings, c.error(msg, causer))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) resolveImport(imp Import) error {
|
func (c *Compiler) compileInclude(include *IncludeNode) (TypeSignature, error) {
|
||||||
res, err := c.resolver.Resolve(c.fileStack.Peek(), imp.path)
|
res, err := c.resolver.Resolve(c.fileStack.Peek(), include.path.value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if already imported and available
|
// warn if already included
|
||||||
for _, i := range c.imports {
|
for _, i := range c.imports {
|
||||||
if c.resolver.IsSame(res.Path, i) {
|
if c.resolver.IsSame(res.Path, i) {
|
||||||
return nil
|
c.warn("already included elsewhere", include)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop recursive imports
|
// stop recursive includes
|
||||||
for i := c.fileStack.Current - 1; i >= 0; i-- {
|
for i := c.fileStack.Current - 1; i >= 0; i-- {
|
||||||
if c.resolver.IsSame(res.Path, c.fileStack.items[i]) {
|
if c.resolver.IsSame(res.Path, c.fileStack.items[i]) {
|
||||||
return c.error("recursive import", imp)
|
return nil, c.error("recursive inclusion", include)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
l := NewLexer(res.Source)
|
l := NewLexer(res.Source)
|
||||||
tokens, err := l.Tokenize()
|
tokens, err := l.Tokenize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
parser := NewParser(res.Source, append(c.fileStack.Slice(), res.Path), tokens)
|
parser := NewParser(res.Source, append(c.fileStack.Slice(), res.Path), tokens)
|
||||||
p, err := parser.Parse(res.Path)
|
p, err := parser.Parse(res.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldSrc := c.source
|
oldSrc := c.source
|
||||||
|
|
||||||
// update source for more descriptive errors
|
// update source for more descriptive errors
|
||||||
c.source = []rune(res.Source)
|
c.source = []rune(res.Source)
|
||||||
if err := c.Compile(p); err != nil {
|
t, err := c.Compile(p)
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.source = oldSrc
|
c.source = oldSrc
|
||||||
|
|
||||||
return nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) SetImportsResolver(resolver ImportsResolver) {
|
func (c *Compiler) SetImportsResolver(resolver ImportsResolver) {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ const (
|
||||||
TokenMinus
|
TokenMinus
|
||||||
TokenStar
|
TokenStar
|
||||||
TokenSlash
|
TokenSlash
|
||||||
|
TokenPercent
|
||||||
TokenBang
|
TokenBang
|
||||||
TokenSemicolon
|
TokenSemicolon
|
||||||
|
|
||||||
|
|
@ -55,7 +56,7 @@ const (
|
||||||
TokenVar
|
TokenVar
|
||||||
TokenIf
|
TokenIf
|
||||||
TokenElse
|
TokenElse
|
||||||
TokenImport
|
TokenInclude
|
||||||
TokenType
|
TokenType
|
||||||
TokenFor
|
TokenFor
|
||||||
TokenIn
|
TokenIn
|
||||||
|
|
@ -166,8 +167,8 @@ func (t TokenKind) 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:
|
||||||
|
|
@ -195,7 +196,7 @@ var Keywords = map[string]TokenKind{
|
||||||
"nil": TokenNil,
|
"nil": TokenNil,
|
||||||
"if": TokenIf,
|
"if": TokenIf,
|
||||||
"else": TokenElse,
|
"else": TokenElse,
|
||||||
"import": TokenImport,
|
"include": TokenInclude,
|
||||||
"var": TokenVar,
|
"var": TokenVar,
|
||||||
"fn": TokenFunc,
|
"fn": TokenFunc,
|
||||||
"return": TokenReturn,
|
"return": TokenReturn,
|
||||||
|
|
@ -268,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 ')':
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ const (
|
||||||
AccessNodeType
|
AccessNodeType
|
||||||
AliasNodeType
|
AliasNodeType
|
||||||
IndexNodeType
|
IndexNodeType
|
||||||
|
IncludeNodeType
|
||||||
BreakpointNodeType
|
BreakpointNodeType
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -294,6 +295,7 @@ const (
|
||||||
BinarySubtraction
|
BinarySubtraction
|
||||||
BinaryMultiplication
|
BinaryMultiplication
|
||||||
BinaryDivision
|
BinaryDivision
|
||||||
|
BinaryModulo
|
||||||
|
|
||||||
BinaryBooleanAnd
|
BinaryBooleanAnd
|
||||||
BinaryBooleanOr
|
BinaryBooleanOr
|
||||||
|
|
@ -317,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:
|
||||||
|
|
@ -690,6 +694,25 @@ func (n AliasNode) Bounds() (Pos, Pos) {
|
||||||
return n.start, n.end
|
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 {
|
type IndexNode struct {
|
||||||
source Node
|
source Node
|
||||||
index Node
|
index Node
|
||||||
|
|
|
||||||
|
|
@ -95,39 +95,21 @@ func NewParser(source string, trace []string, tokens []Token) *Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
Imports []Import
|
|
||||||
Block *BlockNode
|
Block *BlockNode
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Import struct {
|
|
||||||
path string
|
|
||||||
start Pos
|
|
||||||
end Pos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i Import) Bounds() (Pos, Pos) {
|
|
||||||
return i.start, i.end
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) String() string {
|
func (p *Program) String() string {
|
||||||
builder := strings.Builder{}
|
sb := strings.Builder{}
|
||||||
|
|
||||||
builder.WriteString("=== Imports ===\n")
|
sb.WriteString(fmt.Sprintf("=v= program %s =v=\n", p.Path))
|
||||||
for _, i := range p.Imports {
|
sb.WriteString(p.Block.String())
|
||||||
builder.WriteString(i.path)
|
sb.WriteString(fmt.Sprintf("=^= program %s =^=\n", p.Path))
|
||||||
builder.WriteString("\n")
|
|
||||||
}
|
|
||||||
builder.WriteString("===============\n")
|
|
||||||
|
|
||||||
builder.WriteString(p.Block.String())
|
return sb.String()
|
||||||
|
|
||||||
return builder.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) Parse(path string) (*Program, error) {
|
func (p *Parser) Parse(path string) (*Program, error) {
|
||||||
imports := make([]Import, 0)
|
|
||||||
|
|
||||||
// top level statements
|
// top level statements
|
||||||
statements := make([]Node, 0)
|
statements := make([]Node, 0)
|
||||||
|
|
||||||
|
|
@ -135,20 +117,6 @@ func (p *Parser) Parse(path string) (*Program, error) {
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
for int(p.pos) < len(p.tokens) && p.curr.Type != TokenEOF {
|
for int(p.pos) < len(p.tokens) && p.curr.Type != TokenEOF {
|
||||||
if p.accept(TokenImport) {
|
|
||||||
start := p.prev.Start
|
|
||||||
if err := p.expect(TokenString, "import requires a path/name to import"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
imports = append(imports, Import{
|
|
||||||
p.prev.Lexeme[1 : len(p.prev.Lexeme)-1],
|
|
||||||
start,
|
|
||||||
p.prev.End,
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for p.accept(TokenNewLine) {
|
for p.accept(TokenNewLine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +136,6 @@ func (p *Parser) Parse(path string) (*Program, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Program{
|
return &Program{
|
||||||
imports,
|
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
statements,
|
statements,
|
||||||
0,
|
0,
|
||||||
|
|
@ -415,6 +382,25 @@ func (p *Parser) expression(mustBeBlock bool) (Node, error) {
|
||||||
p.prev.End,
|
p.prev.End,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
case TokenInclude:
|
||||||
|
p.advance()
|
||||||
|
start := p.prev.Start
|
||||||
|
|
||||||
|
if err := p.expect(TokenString, "import requires a path/name to include"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IncludeNode{
|
||||||
|
&StringNode{
|
||||||
|
p.prev.Lexeme[1 : len(p.prev.Lexeme)-1],
|
||||||
|
p.prev.Lexeme,
|
||||||
|
p.prev.Start,
|
||||||
|
p.prev.End,
|
||||||
|
},
|
||||||
|
start,
|
||||||
|
p.prev.End,
|
||||||
|
}, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
s, err := p.binary()
|
s, err := p.binary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -448,7 +434,7 @@ func (p *Parser) expression(mustBeBlock bool) (Node, error) {
|
||||||
|
|
||||||
func isBinaryOperator(tokenType TokenKind) bool {
|
func isBinaryOperator(tokenType TokenKind) bool {
|
||||||
switch tokenType {
|
switch tokenType {
|
||||||
case TokenPlus, TokenMinus, TokenStar, TokenSlash, TokenPipe, TokenDoubleAmpersand, TokenDoublePipe, TokenEquals, TokenBangEquals, TokenLessThan, TokenLessThanOrEqual, TokenGreaterThan, TokenGreaterThanOrEqual:
|
case TokenPlus, TokenMinus, TokenStar, TokenSlash, TokenPercent, TokenPipe, TokenDoubleAmpersand, TokenDoublePipe, TokenEquals, TokenBangEquals, TokenLessThan, TokenLessThanOrEqual, TokenGreaterThan, TokenGreaterThanOrEqual:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
@ -461,10 +447,12 @@ func binaryPrecedence(op TokenKind) int {
|
||||||
return 1
|
return 1
|
||||||
case TokenEquals, TokenBangEquals, TokenLessThan, TokenGreaterThan, TokenLessThanOrEqual, TokenGreaterThanOrEqual:
|
case TokenEquals, TokenBangEquals, TokenLessThan, TokenGreaterThan, TokenLessThanOrEqual, TokenGreaterThanOrEqual:
|
||||||
return 2
|
return 2
|
||||||
case TokenPlus, TokenMinus, TokenPipe:
|
case TokenPercent:
|
||||||
return 3
|
return 3
|
||||||
case TokenStar, TokenSlash:
|
case TokenPlus, TokenMinus, TokenPipe:
|
||||||
return 5
|
return 5
|
||||||
|
case TokenStar, TokenSlash:
|
||||||
|
return 10
|
||||||
default:
|
default:
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
@ -480,6 +468,8 @@ func tokenToBinaryOperation(tokenType TokenKind) BinaryOperation {
|
||||||
return BinaryMultiplication
|
return BinaryMultiplication
|
||||||
case TokenSlash:
|
case TokenSlash:
|
||||||
return BinaryDivision
|
return BinaryDivision
|
||||||
|
case TokenPercent:
|
||||||
|
return BinaryModulo
|
||||||
case TokenPipe:
|
case TokenPipe:
|
||||||
panic("unimplemented bitwise ops")
|
panic("unimplemented bitwise ops")
|
||||||
case TokenDoubleAmpersand:
|
case TokenDoubleAmpersand:
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ func (s *StringSignature) Equal(other TypeSignature) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*StringSignature) String() string {
|
func (*StringSignature) String() string {
|
||||||
return "string"
|
return "str"
|
||||||
}
|
}
|
||||||
|
|
||||||
type FloatSignature struct{}
|
type FloatSignature struct{}
|
||||||
|
|
@ -407,7 +407,7 @@ func (s *FunctionSignature) Equal(other TypeSignature) bool {
|
||||||
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 {
|
||||||
|
|
@ -418,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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -810,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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue