Browse Source

Try different classes of operators.

Beoran 4 years ago
parent
commit
f17e62d27c
4 changed files with 101 additions and 34 deletions
  1. 15 4
      README.md
  2. 26 4
      lexer.go
  3. 54 24
      parser.go
  4. 6 2
      token.go

+ 15 - 4
README.md

@@ -20,10 +20,21 @@ periods. A chain consists of one or more commands, linked together by operators.
 - A command chain consists of commands chained together with operators.
   A command chain is evaluated by looking up and calling the the first operator 
   in the chain, which receives the first command and the rest of the chain as 
-  callable  substitutions, which have not been substituted yet. The operator 
-  implementation can then choose to evaluate the substitutions as needed. 
-  For example: ls | grep "foo" | sort > fopen "foo"
-  is evaluated as: > (| (| (ls) (grep "foo")) (sort)) (fopen "foo")
+  arguments. 
+- There are tree kinds of operators: substitute operators,
+  block operators, and shuffle operators. 
+- Substitute operators begin with one of +-*/ and will receive their arguments 
+  as already evaluated substitutions.
+- Block operators begin with one of |&<> and will recieve their arguments
+  as unevaluated blocks.  
+- Shuffle operators begin with one of ,; are interpreted as commands and the 
+  first operand will be an evaluated block, but the second operand is passed
+  as is. 
+  Examples: 
+  $door , open -> , $door open
+  $door , key , drop ->  , (, key $door) drop 
+  ls | grep "foo" | sort > fopen "foo" -> | ls grep "foo" 
+  is evaluated as: > | (| (ls) (grep "foo")) (sort)) fopen "foo"
 - A command may be a direct command, a substitution, or a literal value.
 - A direct command consists of a name followed by zero or more parameters.
   A direct command is evaluated as follows: the name is looked up

+ 26 - 4
lexer.go

@@ -140,7 +140,11 @@ func (lexer *Lexer) MakeToken(kind TokenKind) Token {
 		return lexer.MakeErrorValueToken(kind)
 	case TokenKindWord:
 		return lexer.MakeWordValueToken(kind)
-    case TokenKindOperator:
+    case TokenKindOperator: 
+        fallthrough
+    case TokenKindRedirect: 
+        fallthrough
+    case TokenKindMethod: 
 		return lexer.MakeWordValueToken(kind)
     case TokenKindNil:
         fallthrough
@@ -296,8 +300,20 @@ func isComment(r rune) bool {
 }
 
 func isOperator(r rune) bool {
-	return r == '+' || r == '-' || r == '*' || r == '/' || r == '^' || 
-		   r == '|' || r == '&' || r == ',' || r == '%' || r == '~'
+	return isPureOperator(r) || isRedirect(r) || isMethod(r)
+}
+
+func isPureOperator(r rune) bool {
+	return r == '+' || r == '-' || r == '*' || r == '/' || r == '^' ||
+           r == '%' || r == '~'
+}
+
+func isRedirect(r rune) bool {
+	return r == '|' || r == '&' || r == '>' || r == '<' || r == '@'
+}
+
+func isMethod(r rune) bool {
+	return r == ',' || r == ';'
 }
 
 
@@ -369,7 +385,13 @@ func (lexer *Lexer) LexOperator() Token {
 	if err != nil {
 		return lexer.MakeErrorfToken("when parsing operator: %s", err)
 	}
-	return lexer.MakeToken(TokenKindOperator)
+    oper := lexer.buffer[0]
+    switch {
+        case isPureOperator(oper): return lexer.MakeToken(TokenKindOperator)
+        case isRedirect(oper): 	return lexer.MakeToken(TokenKindRedirect)
+        case isMethod(oper): return lexer.MakeToken(TokenKindMethod)    
+    }
+    return lexer.MakeToken(TokenKindOperator)
 }
 
 func (lexer *Lexer) LexNumber() Token {

+ 54 - 24
parser.go

@@ -67,18 +67,20 @@ for easier shunting the operator into commands:
 PROGRAM -> STATEMENTS .
 STATEMENTS -> STATEMENT STATEMENTS | .
 STATEMENT -> BLOCK | CHAIN eos | eos .
-CHAIN -> COMMAND LINKS . 
-LINKS -> LINK LINKS | .
-LINK -> operator EXPRESSION .  
-EXPRESSION -> COMMAND | SUBSTITUTION | LITERAL . 
-COMMAND -> NAME PARAMETERS .
-PARAMETER -> NAME | LITERAL | SUBSTITUTION | BLOCK .
-SUBSTITUTION -> PARENTHESIS | GETTER | SETTER | LIST .
-PARENTHESIS -> openparen CHAIN closeparen .
+CHAIN -> EXPRESSION LINKS . 
+LINKS -> LINK | .
+LINK -> OPERATOR CHAIN .
+OPERATOR -> evaluator | redirect | blockopt .
+EXPRESSION -> COMMAND | SUBSTITUTION |  LITERAL .
+COMMAND -> NAME PARAMETERS.
+PARAMETERS -> PARAMETER PARAMETERS | .
+PARAMETER -> LITERAL | BLOCK |  SUBSTITUTION | NAME .
+SUBSTITUTION ->  GETTER | SETTER | LIST | PARENTHESIS .
+PARENTHESIS -> closeparen CHAIN openparen .
 BLOCK -> openblock STATEMENTS closeblock .
 LIST -> openlist PARAMETERS closelist .
-LITERAL -> string | int | float | true | false | nil .
-NAME -> word | type | symbol .
+LITERAL -> string | int | float .
+NAME -> word | symbol | type .
 SETTER -> set PARAMETER PARAMETER . 
 GETTER -> get PARAMETER .
 
@@ -535,7 +537,7 @@ func (parser Parser) NextIsName() bool {
 }
 
 func (parser Parser) NextIsOperator() bool {
-    return parser.NextIs(TokenKindOperator)
+    return parser.NextIs(TokenKindOperator, TokenKindRedirect, TokenKindMethod)
 }
 
 func (parser Parser) NextIsArgument() bool {
@@ -575,6 +577,43 @@ func (parser Parser) NextIsStatement() bool {
 	return parser.NextIsChain() || parser.NextIsBlock() || parser.NextIsEOX()
 }
 
+func newChain(oper Token, expr1, expr2 *Ast) * Ast {
+    var astkind AstKind = AstKindParenthesis
+    
+    if oper.TokenKind == TokenKindRedirect {
+        astkind = AstKindStatements
+    } else if oper.TokenKind == TokenKindMethod {
+        chain := NewAstWithToken(AstKindOperation, oper)
+        chain.AppendChildren(expr1, expr2)
+        return chain
+    }
+    
+    subst1 := NewAstWithToken(astkind, oper)
+    subst1.AppendChildren(expr1)
+    subst2 := NewAstWithToken(astkind, oper)
+    subst2.AppendChildren(expr2)
+    chain := NewAstWithToken(AstKindOperation, oper)
+    chain.AppendChildren(subst1, subst2)
+    return chain
+}
+
+func composeChain(oper Token, chain, nextExpr *Ast) * Ast {
+    var astkind AstKind = AstKindParenthesis
+    
+    if oper.TokenKind == TokenKindRedirect {
+        astkind = AstKindStatements
+    } else if oper.TokenKind == TokenKindMethod {
+        chain.AppendChildren(nextExpr)
+        return chain
+    }
+
+    subst := NewAstWithToken(astkind, oper)
+    subst.AppendChildren(nextExpr)
+    newChain := NewAstWithToken(AstKindOperation, oper)
+    newChain.AppendChildren(chain, subst)
+    return newChain
+}
+
 func (parser *Parser) ParseChain() *Ast {
     expression := parser.ParseExpression()
     if !parser.NextIsOperator() {
@@ -584,7 +623,7 @@ func (parser *Parser) ParseChain() *Ast {
     var expressions = []*Ast{ expression }
     var operators = []Token {}
     for parser.NextIsOperator() {
-        oper := parser.Require(TokenKindOperator)
+        oper := parser.Require(TokenKindOperator, TokenKindRedirect, TokenKindMethod)
         expression := parser.ParseExpression()
         if expression == nil {
             parser.Panicf("Expected expression after operator.")
@@ -592,7 +631,7 @@ func (parser *Parser) ParseChain() *Ast {
         expressions = append(expressions, expression)
         operators = append(operators, oper)
     }
-    // now there are N expressions and N - 1 operators, iterate backwards
+    // Now there are N expressions and N - 1 operators, iterate
     // for easy composition
     var chain *Ast
     
@@ -601,19 +640,10 @@ func (parser *Parser) ParseChain() *Ast {
         oper := operators[j]
         if chain == nil {
             expression2 := expressions[i+1]
-            subst1 := NewAstWithToken(AstKindParenthesis, oper)
-            subst1.AppendChildren(expression)
-            subst2 := NewAstWithToken(AstKindParenthesis, oper)
-            subst2.AppendChildren(expression2)
-            chain = NewAstWithToken(AstKindOperation, oper)
-            chain.AppendChildren(subst1, subst2)
+            chain = newChain(oper, expression, expression2) 
             i++
         } else {
-            subst := NewAstWithToken(AstKindParenthesis, oper)
-            subst.AppendChildren(expression)
-            newChain := NewAstWithToken(AstKindOperation, oper)
-            newChain.AppendChildren(chain, subst)
-            chain = newChain
+            chain = composeChain(oper, chain, expression)
         }
     }
     return chain

+ 6 - 2
token.go

@@ -29,7 +29,9 @@ const (
 	TokenKindWord       = TokenKind('w')
 	TokenKindType       = TokenKind('t')
 	TokenKindOperator   = TokenKind('o')
-	TokenKindGet        = TokenKind('$')
+	TokenKindRedirect   = TokenKind('R')
+    TokenKindMethod     = TokenKind('M')	
+    TokenKindGet        = TokenKind('$')
 	TokenKindSet        = TokenKind('=')
 	TokenKindOpenBlock  = TokenKind('{')
 	TokenKindCloseBlock = TokenKind('}')
@@ -54,6 +56,8 @@ var TokenKindNames map[TokenKind]string = map[TokenKind]string{
 	TokenKindWord:       "Word",
 	TokenKindType:       "Type",
 	TokenKindOperator:   "Operator",   
+	TokenKindRedirect:   "Redirect",
+    TokenKindMethod:     "Method",
 	TokenKindGet:        "Get",
 	TokenKindSet:        "Set",
 	TokenKindOpenBlock:  "OpenBlock",
@@ -133,4 +137,4 @@ func (token Token) IsNone() bool {
 
 func (token Token) IsError() bool {
 	return token.TokenKind == TokenKindError
-}
+}