Skip to content

Repository files navigation

Jaina · Gem Version

Simple programming language builder inspired by interpreter pattern. You can build your own languages with custom operands and operators for any project purposes.

Installation

gem'jaina'
$ bundle install
# --- or ---
$ gem install 'jaina'
require'jaina'

Usage


Registered operators

  • AND
  • OR
  • NOT
  • (, ) (grouping operators)

Register your own operator

# 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)

Register your own operand

# 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)

Context API

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

Parse your code (build AST)

# 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>

Evaluate your code

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)

Custom operator/operand arguments

# 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"endend

List and fetch registered operands and operators

A=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

Full example

# 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

Contributing

  • 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

License

Released under MIT License.

Authors

Rustam Ibragimov

About

Simple programming language builder inspired by interpreter pattern. You can build your own languages with custom operands and operators for any project purposes.

Topics

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages