Simple programming language builder inspired by interpreter pattern. You can build your own languages with custom operands and operators for any project purposes.
gem'jaina'$ bundle install
# --- or ---
$ gem install 'jaina'require'jaina'- Registered operators
- Register your own operator
- Register your own operand
- Context API
- Parse your code (build AST)
- Evaluate your code
- Custom operator/operand arguments
- List registered operands and operators
- Full example
ANDORNOT(,)(grouping operators)
# step 1: define new operatorclassBut < Jaina::NonTerminalExprtoken'BUT'# use it in your program :)associativity_direction:left# associativity (left or right)acts_as_binary_term# binar or unaryprecedence_level4# for example: AND > OR, NOT > AND, and etc...end# step 2: regsiter your operatorJaina.register_expression(But)# step 1: define new operandclassA < Jaina::TerminalExprtoken'A'# NOTE: context is a custom data holder that passed from expression to expressiondefevaluate(context)# your custom evaluation codeendend# step 2: regsiter your operandJaina.register_expression(A)# step X: redefine existing operand (with the same token)classNewA < Jaina::TerminalExprtoken'A'endJaina.redefine_expression(NewA)classA < Jaina::TerminalExpr# ... some codedefevaluate(context)
... yourcode ...
# ... context ???
... yourcode ...
endend# NOTE: context apicontext.keys# => []context.set(:a,1)# => 1context.get(:a)# => 1context.keys# => [:a]context.get(:b)# => Jaina::Parser::AST::Contex::UndefinedContextKeyError# NOTE: without argumentsJaina.parse('A AND B AND (C OR D) OR A AND (C OR E)')# => #<Jaina::Parser::AST:0x00007fd6f424a2e8># NOTE: with argumentsJaina.parse('A[1,2] AND B[3,4]')# => #<Jaina::Parser::AST:0x00007fd6f424a2e9>ast=Jaina.parse('A AND B[5,test] AND (C OR D) OR A AND (C OR E)')ast.evaluate# --- or ---Jaina.evaluate('A AND B[5,test] AND (C OR D) OR A AND (C OR E)')# --- you can set initial context of your program ---Jaina.evaluate('A AND B[5,test]',login: 'admin',logged_in: true)# NOTE: use []Jaina.parse('A[1,true] AND B[false,"false"]')# NOTE:# all your arguments will be typecasted to# the concrete type inferred from the argument literalJaina.parse('A[1,true,false,"false"]')# 1, true, false "false"# NOTE: access to the argument listclassA < Jaina::TerminalExprtoken'A'defevaluate(context)# A[1,true,false,"false"]arguments[0]# => 1arguments[1]# => truearguments[2]# => falsearguments[3]# => "false"endendA=Class.new(Jaina::TerminalExpr){token'A'}B=Class.new(Jaina::TerminalExpr){token'B'}C=Class.new(Jaina::TerminalExpr){token'C'}Jaina.register_expression(A)Jaina.register_expression(B)Jaina.register_expression(C)Jaina.expressions# => ["AND", "OR", "NOT", "(", ")", "A", "B", "C"]Jaina.fetch_expression("AND")# => Jaina::Parser::Expression::Unit::AndJaina.fetch_expression("A")# => AJaina.fetch_expression("KEK")# => raises Jaina::Parser::Expression::Registry::UnregisteredExpressionError# step 1: create new operandclassAddNumber < Jaina::TerminalExprtoken'ADD'defevaluate(context)context.set(:current_value,context.get(:current_value) + 10)endend# step 2: create another new operandclassCheckNumber < Jaina::TerminalExprtoken'CHECK'defevaluate(context)context.get(:current_value) < 0endend# step 4: and another new :)classInitState < Jaina::TerminalExprtoken'INIT'defevaluate(context)initial_value=arguments[0] || 0context.set(:current_value,initial_value)endend# step 5: register new oeprandsJaina.register_expression(AddNumber)Jaina.register_expression(CheckNumber)Jaina.register_expression(InitState)# step 6: run your program# NOTE: with initial contextJaina.evaluate('CHECK AND ADD',current_value: -1)# => 9Jaina.evaluate('CHECK AND ADD',current_value: 2)# => false# NOTE: without initial contextJaina.evaluate('INIT AND ADD')# => 10Jaina.evaluate('INIT AND (CHECK OR ADD)')# => 10# NOTE: with argumentsJaina.evaluate('INIT[100] AND ADD')=># 112- Fork it ( https://github.com/0exp/jaina/fork )
- Create your feature branch (
git checkout -b feature/my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin feature/my-new-feature) - Create new Pull Request
Released under MIT License.