Procházet zdrojové kódy

Consider adding operators as commands.

Beoran před 5 roky
rodič
revize
07e59b880b
4 změnil soubory, kde provedl 96 přidání a 20 odebrání
  1. 29 1
      builtin.go
  2. 32 2
      lexer.go
  3. 33 17
      parser.go
  4. 2 0
      token.go

+ 29 - 1
builtin.go

@@ -425,6 +425,25 @@ func exit(vm *VM, val ...Value) [] Value {
 	return Ok()
 }
 
+func comma(vm * VM, val ...Value) []Value {
+    if len(val) < 2 {
+        return Fail(fmt.Errorf("Need at least 2 arguments"))
+    }
+    
+    target := val[0]
+    command := val[1]
+    val[1] = target
+    val = val[1:]
+    
+    if call, isCall := command.(Callable); isCall { 
+        return vm.CallCallable(call, val...)
+    } else if name, isName := command.(WordValue) ; isName {
+        return vm.CallNamed(name.String(), val...)
+    } else {
+        return Fail(fmt.Errorf("Not callable: %v"))
+    }
+}
+
 
 func (vm *VM) RegisterBuiltinTypes() {
 	vm.RegisterTop("Int", IntType)
@@ -448,7 +467,9 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltinWithHelp("addi", addi, `adds two integers together`).Takes(IntType, IntType).Returns(BoolType)
 	vm.RegisterBuiltinWithHelp("addf", addf, `adds two floats together`).Takes(IntType, IntType).Returns(IntType)
 	vm.RegisterBuiltinWithHelp("andb", andb, `returns true if all it's arguments are true`).Takes(BoolType, BoolType).Returns(BoolType)
-	vm.RegisterBuiltin("cover", cover)
+    vm.RegisterBuiltin(",", comma)
+
+    vm.RegisterBuiltin("cover", cover)
 	vm.RegisterBuiltin("fetchl", fetchl).Takes(ListType, IntType).Returns(AnyType)
 	vm.RegisterBuiltin("fetchm", fetchm).Takes(MapType, AnyType).Returns(AnyType)
 	vm.RegisterBuiltin("sumi", sumi).Takes(IntType, IntType).Returns(IntType)
@@ -483,6 +504,13 @@ func (vm *VM) RegisterBuiltins() {
 			Over("muli", 0, IntType, IntType),
 			Over("mulf", 0, FloatType, IntType),
 			Over("mulf", 0, IntType, FloatType))
+
+	vm.AddOverloads("*", 
+			Over("mulf", 0, FloatType, FloatType),
+			Over("muli", 0, IntType, IntType),
+			Over("mulf", 0, FloatType, IntType),
+			Over("mulf", 0, IntType, FloatType))
+
 	
 	vm.AddOverloads("add", 
 			Over("addf", 0, FloatType, FloatType),

+ 32 - 2
lexer.go

@@ -140,6 +140,8 @@ func (lexer *Lexer) MakeToken(kind TokenKind) Token {
 		return lexer.MakeErrorValueToken(kind)
 	case TokenKindWord:
 		return lexer.MakeWordValueToken(kind)
+    case TokenKindOperator:
+		return lexer.MakeWordValueToken(kind)
     case TokenKindNil:
         fallthrough
 	case TokenKindBoolean:
@@ -293,6 +295,12 @@ func isComment(r rune) bool {
 	return r == '#'
 }
 
+func isOperator(r rune) bool {
+	return r == '+' || r == '-' || r == '*' || r == '/' || r == '^' || 
+		   r == '|' || r == '&' || r == ',' || r == '%' || r == '~'
+}
+
+
 func (lexer *Lexer) SkipSpace() error {
 	_, err := lexer.SkipWhile(isSpace)
 	return err
@@ -356,11 +364,22 @@ func (lexer *Lexer) handleError(err error) Token {
 	}
 }
 
+func (lexer *Lexer) LexOperator() Token {
+	_, err := lexer.NextWhile(isOperator)
+	if err != nil {
+		return lexer.MakeErrorfToken("when parsing operator: %s", err)
+	}
+	return lexer.MakeToken(TokenKindOperator)
+}
+
 func (lexer *Lexer) LexNumber() Token {
 	isFloat := false
+	maybeOperator := false
+	reallyOperator := false
 
 	// skip any first - or +
-	_, err := lexer.NextIf(func(r rune) bool {
+	_, err := lexer.NextIf(func(r rune) bool {		
+		maybeOperator = (r == '-' || r == '+')  // it might also be an operator in stead.
 		return r == '-' || r == '+'
 	})
 
@@ -374,14 +393,21 @@ func (lexer *Lexer) LexNumber() Token {
 				isFloat = true
 				return true
 			}
+		} else if maybeOperator {
+			reallyOperator = true
+			return true
 		} else {
 			return false
 		}
 	})
-
+	
 	if err != nil {
 		return lexer.MakeErrorfToken("when parsing number: %s", err)
 	}
+	if maybeOperator && reallyOperator {
+		 return lexer.LexOperator()
+	}
+	
 	if isFloat {
 		return lexer.MakeToken(TokenKindFloat)
 	} else {
@@ -668,6 +694,10 @@ func (lexer *Lexer) lex() Token {
 	if r == ':' {
 		return lexer.LexSymbol()
 	}
+	
+	if isOperator(r) {
+		return lexer.LexOperator()
+	}
 
 	switch TokenKind(r) {
 	case TokenKindGet:

+ 33 - 17
parser.go

@@ -37,17 +37,19 @@ GETTER -> get ORIGIN .
 ORIGIN -> word | SETTER | GETTER .
 
 
-Or with methods variant
+Or with simple operators variant.
 
 PROGRAM -> STATEMENTS.
 CLOSED -> BLOCK | LIST | PARENTHESIS .
 STATEMENTS -> STATEMENT STATEMENTS | .
 STATEMENT -> CLOSED | EXPRESSION eos | eos .
-COMMAND -> word PARAMETERS.
+COMMAND -> WORDVALUE DETAILS .
+DETAILS -> OPERATION | PARAMETERS .
+OPERATION -> operator COMMAND .
 PARAMETERS -> PARAMETER PARAMETERS | .
 PARAMETER -> WORDVALUE | GETTER | SETTER | CLOSED .
-EXPRESSION -> COMMAND | GETTER | SETTER | METHODCALL .
-PARENTHESIS -> closeparen EXPRESSION openparen .
+EXPRESSION -> COMMAND | GETTER | SETTER.
+PARENTHESIS -> openparen EXPRESSION closeparen .
 BLOCK -> openblock STATEMENTS closeblock .
 LIST -> openlist PARAMETERS closelist .
 VALUE -> string | int | float | symbol | type .
@@ -55,8 +57,8 @@ WORDVALUE -> word | VALUE.
 SETTER -> set TARGET . 
 TARGET -> word PARAMETER | GETTER PARAMETER .
 GETTER -> get ORIGIN .
+GETCALL -> comma COMMAND | .
 ORIGIN -> word | SETTER | GETTER .
-METHODCALL -> VALUE word PARAMETERS .
 
  *
  * program -> statements
@@ -183,6 +185,8 @@ func AstKindForToken(token Token) AstKind {
 			 return AstKindValue
 		case TokenKindWord:
 			 return AstKindWord
+        case TokenKindOperator:
+			 return AstKindWord
 		case TokenKindType:
 			return AstKindType
 		default:
@@ -381,12 +385,28 @@ func (parser *Parser) ParseGet() *Ast {
 	return ast
 }
 
+func (parser *Parser) ParseOperator(operand *Ast) *Ast {
+    parser.LogDebug("ParseOperator: %s\n", parser.current.String())
+    
+    operator := parser.Require(TokenKindOperator)
+    arguments := parser.ParseArguments(operand)
+    command := NewAstWithToken(AstKindCommand, operator)
+    command.AppendChild(arguments)
+    return command
+}
+
 func (parser *Parser) ParseCommand() *Ast {
     parser.LogDebug("ParseCommand: %s\n", parser.current.String())
 
-	word := parser.Require(TokenKindWord, TokenKindType)
-	arguments := parser.ParseArguments()
-	command := NewAstWithToken(AstKindCommand, word)
+    wordvalue := parser.ParseWordValue()
+    
+    // operator command
+    if parser.NextIs(TokenKindOperator) {
+        return parser.ParseOperator(wordvalue)
+    } 
+    
+    arguments := parser.ParseArguments()
+	command := NewAstWithToken(AstKindCommand, wordvalue.Token())
 	command.AppendChild(arguments)
 	return command
 }
@@ -403,14 +423,6 @@ func (parser *Parser) ParseClosed() *Ast {
 	}
 }
 
-func (parser *Parser) ParseMethodCall() *Ast {
-	value := parser.ParseValue()
-	word := parser.Require(TokenKindWord, TokenKindType)
-	command := NewAstWithToken(AstKindCommand, word)
-	arguments := parser.ParseArguments(value)	
-	command.AppendChild(arguments)
-	return command
-}
 
 func (parser *Parser) ParseExpression() *Ast {
     parser.LogDebug("ParseExpression: %s\n", parser.current.String())
@@ -419,7 +431,7 @@ func (parser *Parser) ParseExpression() *Ast {
 		case parser.NextIsWord(): return parser.ParseCommand()
 		case parser.NextIsSet(): return parser.ParseSet()
 		case parser.NextIsGet(): return parser.ParseGet()
-		case parser.NextIsValue(): return parser.ParseMethodCall()
+		case parser.NextIsValue(): return parser.ParseCommand()
 		default: 
 			parser.Panicf("Syntax error in expression, expected word, $, =, value")
 			return nil
@@ -484,6 +496,10 @@ func (parser Parser) NextIsValue() bool {
     TokenKindSymbol)
 }
 
+func (parser Parser) NextIsOperator() bool {
+    return parser.NextIs(TokenKindOperator)
+}
+
 func (parser Parser) NextIsWordValue() bool {
     return parser.NextIs(TokenKindWord, TokenKindString, TokenKindType, 
     TokenKindInteger, TokenKindFloat, TokenKindBoolean, TokenKindNil,

+ 2 - 0
token.go

@@ -28,6 +28,7 @@ const (
     TokenKindNil        = TokenKind('N')
 	TokenKindWord       = TokenKind('w')
 	TokenKindType       = TokenKind('t')
+	TokenKindOperator   = TokenKind('o')
 	TokenKindGet        = TokenKind('$')
 	TokenKindSet        = TokenKind('=')
 	TokenKindOpenBlock  = TokenKind('{')
@@ -52,6 +53,7 @@ var TokenKindNames map[TokenKind]string = map[TokenKind]string{
     TokenKindNil:        "Nil",
 	TokenKindWord:       "Word",
 	TokenKindType:       "Type",
+	TokenKindOperator:   "Operator",   
 	TokenKindGet:        "Get",
 	TokenKindSet:        "Set",
 	TokenKindOpenBlock:  "OpenBlock",