Skip to content

Parser Command Reference

Abe Pralle edited this page Aug 8, 2024 · 18 revisions

A .froley file should have one parser section which is comprised of any number of routines.

The Parser turns a token stream into an Abstract Syntax Tree (AST) of extended Cmd nodes.

Routines

- routine_name
  ...  # commands

- another_routine
  ...

- routine3
  if (...) return      # returns 0 by default
  if (...) return 5    # can return any integer
  if (...) return true # 'true' and 'false' are returned as '1' and '0'

- routine4
  if (routine3) println "success"

The topmost routine is the default routine. It is called to parse a token stream by default; other Parser routines may be explicitly called if desired.

Routines cannot accept arguments - use global variables if needed. Routines implicitly return an integer. return returns "0" by default.

Parser routines automatically return at the end if no explicit return command is given.

Variables

count = 0
if (consume('{')) ++count
...
  • Variables are created simply by assigning a value to a name.
  • All variables are global variables (accessible to all Parser routines).
  • Variables are statically typed. The static type of a variable is implicitly determined by the type of the first value assigned it.
  • Variables can be used to pass values into or out of routines.

Built-in Variables

Name Description
content Read-only. See Creating Nodes.
disable_output Incrementing or setting to non-zero causes node creation commands to have no effect (createNull, produce NodeType(...), produceList, etc.). This allows parsing through source code for purposes other than creating an AST.

Literals

Example Description
"abc" A String
'a' A Character
123 An Integer
true Logical true
false Logical false
`(-1.0).acos` A Native Literal expression (see Creating Nodes)

Strings and Characters are mostly interchangeable. The only caveat is if the initial value of a variable is a Character, it will not be able to later store a String.

Statements

Statement Description
++ Increment operator. Increment variables with ++varname or varname++.
-- Decrement operator. Decrement variables with --varname or varname--.
-> NodeType(...) -> is an alias for produce.
create NodeType
create NodeType(args)
Push a new Cmd node on the internal stack and continue execution. See Creating Nodes.
createList
createList ListType
Creates a CmdList or extended CmdList node that contains all the nodes on the stack since the most recent beginList command. The resulting list is pushed back on the stack.
createNull Pushes a null reference onto the node stack.
createTokenList Pushes a TokenList node onto the node stack that contains all the .tokens:Token[] that have been read since the most recent call to savePosition. The saved position is consumed and the command stack is discarded back to the save position. See also createTokenListPreservingStack and produceTokenList.
createTokenListPreservingStack Like createTokenList but preserves the command stack's contents.
discardList Cancels the most recent beginList. The stack is unaltered.
discardPosition Discards the most recent savePosition.
mustConsume("symbol")
mustConsume(TOKEN_TYPE)
If the next token matches the specified type, read and discard it. Otherwise throw an error.
mustConsume(@"content") If the string [content] of the next token matches the specified type, read and discard it. Otherwise throw an error.
noAction Does nothing. Useful as a placeholder single command for if & while.
pop varname Pops a Cmd node off the command stack and stores it in varname, which will be automatically created as a global variable if it doesn't already exist.
print arg1 [arg2...] Prints one or more expressions without a newline.
println arg1 [arg2...] Prints one or more expressions followed by a newline.
produce NodeType
produce NodeType(args)
Executes a create NodeType(...) and then returns from the current routine.
produceNull Pushes a null reference on the stack and then returns from the current routine.
produceList
produceList ListType
Executes a createList ... and then returns from the current routine.
produceTokenList Executes createTokenList and then returns from the current routine.
produceTokenListPreservingStack Executes createTokenListPreservingStack and then returns from the current routine.
push varname Pushes the Cmd node value of variable varname onto the command stack.
restorePosition Rewinds the input to the point of the most recent savePosition.
return Returns from the current routine. If execution reaches the end of a parser routine a return happens automatically.
savePosition Saves the current input position (line and column, etc.) to be either rewound to with restorePosition or else discarded with discardPosition.
syntaxError
syntaxError "message"
Throws a CompileError with either a default "unexpected input" message or a custom message.

Control Structures

Control Structure Description
if (condition) ...
elseIf (condition) ...
else ...
Single line if statement; separate multiple commands with ;.
if (condition)
  ...
elseIf (condition)
 ...
else
  ...
endIf
Multi-line line if statement.
on token‑type
on @"content"
onPeek token‑type
onPeek @"content"
  ...
elseOn token‑type
elseOnPeek token‑type
  ...
elseOnOthers
  ...
endOn
on and elseOn consume the next token if it matches the specified type and make it the "current token". onPeek and elseOnPeek set current token to be the next token without consuming it. The current token is stored with any new Cmd node created within the on block. "on" and "onPeek" variations can be mixed & matched - for example on ... elseOnPeek ... or onPeek ... elseOn .... elseOnOthers does not consume the next token or change the current token; it is just the version of "else" for "on".


The @"content" variations check the string [content] of the next token rather than the token type.

on/onPeek token‑type additional‑terms ‑> NodeType(...) on-produce is a shorthand version of on that allows a list of additional routine calls and token types to be specified after the initial token type. The on performs a matching decision on the first token type and then treats the remaining parse terms as "must-reads". For example, on '(' expression ')' -> Expression(operand) is equivalent to:

on '('
  expression
  expression
  mustConsume(')')
produce Expression(operand)
endOn
while (condition) ... Single line while loop; separate multiple commands with ;.
while (condition)
  ...
endWhile
Multi-line while loop.

Expressions

Expressions result in a value that can be used as a condition for if or while. They can also be used as standalone statements.

Operators

Operator Description
( expression ) Standard precedence operator.
+, -, *, /, ^ Add, subtract, multiply, divide, power.
==, !=, <=, >=, <, > Comparison Operators
not Logical not - if (not hasAnother) ....
and, or Logical AND and OR. if (hasAnother and nextIs(';')) ....

Functions

Expression Description
routine-name Call the named routine. The routine returns an integer (default: "0").
call user-routine-name Call an arbitrarily-named user routine AKA "native routine". The routine is not defined in the .froley file, but rather in the ParserCore class that Froley generates. Define the method by overriding it in the customizable Parser class which extends ParserCore. User routines return an Int.
consume("symbol")
consume(TOKEN_TYPE)
Read and discard the next token if it matches the specified type. Evaluates to true on success.
consume(@"content") Read and discard the next token if its string content matches the specified value, regardless of token type. Evaluates to true on success. Only tokens with the [content] attribute have string content.
hasAnother Evaluates to true if another input token is available.
nextHasAttribute(attribute-name) Returns true if the next token has the named attribute - if (nextHasAttribute(content)) ....
nextIs("symbol")
nextIs(TOKEN_TYPE)
Evaluates to true if the next available token has the specified type.
nextIs(@"content") Evaluates to true if the string content of the next token matches the specified value regardless of token type. Only tokens with the [content] attribute have string content.
read Reads the next input token.

Creating Nodes

  • Commands create XYZ and produce XYZ will create a new extended Cmd node called XYZ and push it on the stack.
  • If arguments create XYZ(alpha,beta) are given, then XYZ is given properties alpha:Cmd and beta:Cmd. Two values are popped off the stack; the topmost value is assigned to beta and the next value to alpha before the XYZ node is pushed on the stack.
  • Specific property types can be declared: create Routine(name:String,statements:Statements). Each property still pops one node off the stack, but in the case of String or Integer (etc.), that node's to->String or to->Int32 (etc.) method is called to convert the node into a value.
  • There are five built-in types: String, Real, Integer, Character, and Logical. Any other type names are assumed to be the names of extended Cmd types.
  • Node properties can be assigned the value content: on STRING -> LiteralString(value=content). When this happens, instead of popping off a node from the stack, value gets its value from the string content of the associated token. Assigning content to a property makes it a String property by default unless another built-in type is declared.
  • Finally, node properties can be assigned an arbitrary backtick-delimited string of native code called a native literal. The content of the string, as native code, is assigned to the property. For example, create Number(value=`(-1.0).acos`) initializes value with result of the expression (-1.0).acos (the value of π).

Example

From the Simple-Parser scanner example.

--------------------------------------------------------------------------------
parser
--------------------------------------------------------------------------------
- statements
  consume_eols

  beginList
    while (hasAnother)
      on "println"
        arg_list
        create Println(args)
      elseOnOthers
        expression
      endOn
      consume_eols
    endWhile
  produceList Statements

- consume_eols
  while (consume(EOL)) noAction

- arg_list
  beginList
    while (hasAnother and not nextIs(EOL))
      expression
    endWhile
  produceList

- expression
  assign

- assign [rightBinary]
  on "=" -> Assign

- add_subtract [binary]
  on "+" -> Add
  on "-" -> Subtract

- multiply_divide [binary]
  on "*" -> Multiply
  on "/" -> Divide

- power [binary]
  on "^" -> Power

- factorial [postUnary]
  on "!" -> Factorial

- negate [preUnary]
  on "-" -> Negate

- term
  on '(' expression ')': return
  on IDENTIFIER -> Access(name=content)
  on NUMBER     -> Number(value=content:Real)
  on STRING     -> LiteralString(value=content)
  syntaxError

Clone this wiki locally