Page cover

πŸ’»Add Features on Maryl

Here is all you need to know to implement a feature on Maryl

Adding New Syntax

To add new native elements to the language, you'll have to use Megaparsec. Go to src/Parsing/ParserAst.hs and follow these steps:

  • Parse a new symbol:

    • Create a function that parses your new symbol using Megaparsec's Parser (e.g.: pPointer).

    • Call your new function in one of the next steps.

  • Add a new type:

    • In the MarylTypedata type, add your new type.

    • To parse it, add it to the list of types in the types'function. If the type is more complexe and needs extra informations, add its parsing function to the typesfunction directly.

    • Add the translation from String to MarylTypein the getTypefunction.

    • Finally, don't forget to update the documentation so people know which type they can use!

  • Add a new statement:

    • Statements like return, if, loops, should be added to the pTermfunction.

    • Add the newly parsed statement as a new Asttype in the structure.

  • Add a new assignment (=):

    • Just add your new assignment symbol in the eqSymbolfunction.

  • Add a new operator:

    • Maryl parsing for operators is done with the built-in makeExprParserof Megaparsec, so you just have to add your new operator to the operatorTable.

Now that you've added your newly parsed value, you have to add it to the evaluation, in the src/Evalfolder.

Adding Built-in Functions

To add new built-in functions to Maryl, follow these steps:

  1. Define your operator in VirtualMachine/Interpreter.hs:

  1. Register your operator in the operators list:

Extending the Syntax

To add new syntax elements to the language:

  1. Add a new instruction type in VirtualMachine/Instructions.hs:

  1. Create a constructor for your instruction:

  1. Add a parser in VirtualMachine/Parser.hs:

  1. Add your parser to the keyWords list:

  1. Implement the execution logic in VirtualMachine/Interpreter.hs:

Integration with External Libraries

To integrate external libraries with Maryl:

  1. Create a new operator that wraps your external function in VirtualMachine/Interpreter.hs

  2. Use the io function to lift IO operations into the VmState monad:

  1. Register your external function as an operator following the steps in "Adding Built-in Functions"

Or, create a file ending in .mrland its code can be imported in your programs by simply typing:

Remember to:

  • Handle errors appropriately using fail or eitherS

  • Maintain type safety by properly converting between Value and your external types

  • Document any new dependencies in the project's cabal file

Adding a New Operator (Evaluation stage)

To add a new operator, follow these steps:

  1. Define the Operator's Functionality:

    • Implement the evaluation logic in Eval.Ops.

    • The function signature should match others, e.g., evalNewOp :: Memory -> Ast -> Ast -> Either String (Ast, Memory).

  2. Register the Operator:

    • Add the operator to the defaultRegistry in Evaluator.hs:

  3. Specify Return Types:

    • Update assocOpExpectation in Eval.Ops to define the valid return types for the new operator:

Adding a New Operator (Translation stage)

To support a new operator:

  1. Update translateOpInst:

    • Add the new operator and its corresponding VM instruction:

    • If the instruction doesn't exist in VirtualMachine.Instructions, define it there first.

  2. Update isSingleOp:

    • Ensure the operator is marked as a single operator if it doesn't represent a compound assignment:

  3. Test the Operator:

    • Write test cases for the operator to verify correct translation and VM behavior.

Adding New AST Node (Evaluation Stage)

  1. Define the Node:

    • Extend the Ast type in Parsing.ParserAst to include the new node.

  2. Implement Evaluation Logic:

    • Add a case for the new node in evalNode:

  3. Update Supporting Functions:

    • If the new node affects structures like evalAST, applyOp, or memory functions, update those as needed.

Adding New AST Node (Translation Stage)

To support a new AST node:

  1. Extend the AST Definition:

    • Add the new node to the Ast data type in Parsing.ParserAst.

  2. Implement Translation Logic:

    • Add a case for the new node in translateAST:

    • Generate appropriate instructions using the VirtualMachine.Instructions module.

  3. Update Supporting Functions:

    • If the new node interacts with specific constructs (e.g., conditionals or loops), update the relevant translation functions like translateIf or translateLoop.

Adding New Maryl Types

  1. Define the Type:

    • Extend the MarylType enumeration in Parsing.ParserAst.

  2. Update Validation:

    • Update isValidType and isSameType to include the new type.

  3. Add Usage Logic:

    • Modify relevant sections like evalDefinition, evalAssignType, or evalBinaryRet to handle the new type.

Last updated