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 consists of commands chained together with operators.
   A command chain is evaluated by looking up and calling the the first operator 
   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 
   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 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 consists of a name followed by zero or more parameters.
   A direct command is evaluated as follows: the name is looked up
   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)
 		return lexer.MakeErrorValueToken(kind)
 	case TokenKindWord:
 	case TokenKindWord:
 		return lexer.MakeWordValueToken(kind)
 		return lexer.MakeWordValueToken(kind)
-    case TokenKindOperator:
+    case TokenKindOperator: 
+        fallthrough
+    case TokenKindRedirect: 
+        fallthrough
+    case TokenKindMethod: 
 		return lexer.MakeWordValueToken(kind)
 		return lexer.MakeWordValueToken(kind)
     case TokenKindNil:
     case TokenKindNil:
         fallthrough
         fallthrough
@@ -296,8 +300,20 @@ func isComment(r rune) bool {
 }
 }
 
 
 func isOperator(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 {
 	if err != nil {
 		return lexer.MakeErrorfToken("when parsing operator: %s", err)
 		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 {
 func (lexer *Lexer) LexNumber() Token {

+ 54 - 24
parser.go

@@ -67,18 +67,20 @@ for easier shunting the operator into commands:
 PROGRAM -> STATEMENTS .
 PROGRAM -> STATEMENTS .
 STATEMENTS -> STATEMENT STATEMENTS | .
 STATEMENTS -> STATEMENT STATEMENTS | .
 STATEMENT -> BLOCK | CHAIN eos | eos .
 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 .
 BLOCK -> openblock STATEMENTS closeblock .
 LIST -> openlist PARAMETERS closelist .
 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 . 
 SETTER -> set PARAMETER PARAMETER . 
 GETTER -> get PARAMETER .
 GETTER -> get PARAMETER .
 
 
@@ -535,7 +537,7 @@ func (parser Parser) NextIsName() bool {
 }
 }
 
 
 func (parser Parser) NextIsOperator() bool {
 func (parser Parser) NextIsOperator() bool {
-    return parser.NextIs(TokenKindOperator)
+    return parser.NextIs(TokenKindOperator, TokenKindRedirect, TokenKindMethod)
 }
 }
 
 
 func (parser Parser) NextIsArgument() bool {
 func (parser Parser) NextIsArgument() bool {
@@ -575,6 +577,43 @@ func (parser Parser) NextIsStatement() bool {
 	return parser.NextIsChain() || parser.NextIsBlock() || parser.NextIsEOX()
 	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 {
 func (parser *Parser) ParseChain() *Ast {
     expression := parser.ParseExpression()
     expression := parser.ParseExpression()
     if !parser.NextIsOperator() {
     if !parser.NextIsOperator() {
@@ -584,7 +623,7 @@ func (parser *Parser) ParseChain() *Ast {
     var expressions = []*Ast{ expression }
     var expressions = []*Ast{ expression }
     var operators = []Token {}
     var operators = []Token {}
     for parser.NextIsOperator() {
     for parser.NextIsOperator() {
-        oper := parser.Require(TokenKindOperator)
+        oper := parser.Require(TokenKindOperator, TokenKindRedirect, TokenKindMethod)
         expression := parser.ParseExpression()
         expression := parser.ParseExpression()
         if expression == nil {
         if expression == nil {
             parser.Panicf("Expected expression after operator.")
             parser.Panicf("Expected expression after operator.")
@@ -592,7 +631,7 @@ func (parser *Parser) ParseChain() *Ast {
         expressions = append(expressions, expression)
         expressions = append(expressions, expression)
         operators = append(operators, oper)
         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
     // for easy composition
     var chain *Ast
     var chain *Ast
     
     
@@ -601,19 +640,10 @@ func (parser *Parser) ParseChain() *Ast {
         oper := operators[j]
         oper := operators[j]
         if chain == nil {
         if chain == nil {
             expression2 := expressions[i+1]
             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++
             i++
         } else {
         } 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
     return chain

+ 6 - 2
token.go

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