Skip to content

Commit

Permalink
Expand grammar and parser to handle arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
AliOsm committed Oct 12, 2024
1 parent d9b773c commit 52c46c8
Show file tree
Hide file tree
Showing 7 changed files with 584 additions and 387 deletions.
17 changes: 17 additions & 0 deletions lib/zaid/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Parser
left '||'
right '='
left '،'
left '['
preclow

rule
Expand Down Expand Up @@ -65,6 +66,8 @@ class Parser
| Class
| If
| While
| ArrayLiteral
| ArrayAccess
| '(' Expression ')' { result = val[1] }
;

Expand Down Expand Up @@ -170,6 +173,20 @@ class Parser
While:
WHILE Expression THEN Block { result = WhileNode.new(val[1], val[3]) }
;

ArrayLiteral:
'[' ']' { result = ArrayNode.new([]) }
| '[' ElementList ']' { result = ArrayNode.new(val[1]) }
;

ElementList:
Expression { result = [val[0]] }
| ElementList '،' Expression { result = val[0] << val[2] }
;

ArrayAccess:
Expression '[' Expression ']' { result = ArrayAccessNode.new(val[0], val[2]) }
;
end


Expand Down
2 changes: 2 additions & 0 deletions lib/zaid/nodes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require_relative 'nodes/array_access_node'
require_relative 'nodes/array_node'
require_relative 'nodes/break_node'
require_relative 'nodes/call_node'
require_relative 'nodes/class_node'
Expand Down
14 changes: 14 additions & 0 deletions lib/zaid/nodes/array_access_node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

module Zaid
module Nodes
ArrayAccessNode = Struct.new(:array, :index) do
def eval(context)
array_value = array.eval(context)
index_value = index.eval(context)

array_value.ruby_value[index_value.ruby_value]
end
end
end
end
11 changes: 11 additions & 0 deletions lib/zaid/nodes/array_node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module Zaid
module Nodes
ArrayNode = Struct.new(:elements) do
def eval(context)
Constants['مصفوفة'].new_with_value(elements.map { |element| element.eval(context) })
end
end
end
end
861 changes: 474 additions & 387 deletions lib/zaid/parser.rb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/zaid/runtime/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def perform_arithmetic_operation(receiver, arguments, operation, class_name)
Constants['عدد_صحيح'] = Zaid::Runtime::ZaidClass.new(Constants['شيء'])
Constants['عدد_عشري'] = Zaid::Runtime::ZaidClass.new(Constants['شيء'])
Constants['نص'] = Zaid::Runtime::ZaidClass.new(Constants['شيء'])
Constants['مصفوفة'] = Zaid::Runtime::ZaidClass.new(Constants['شيء'])

root_self = Constants['شيء'].new
RootContext = Zaid::Runtime::Context.new(root_self)
Expand Down
65 changes: 65 additions & 0 deletions test/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,70 @@ def test_binary_operator
def test_semicolon
assert_equal NodeList.new([NumberNode.new(5), NumberNode.new(3)]), @parser.parse('٥;٣')
end

def test_array_node
assert_equal NodeList.new([ArrayNode.new([NumberNode.new(1), NumberNode.new(2)])]), @parser.parse('[١، ٢]')
end

def test_array_access_node
assert_equal NodeList.new([ArrayAccessNode.new(ArrayNode.new([NumberNode.new(1), NumberNode.new(2)]), NumberNode.new(0))]),
@parser.parse('[١، ٢][٠]')
end

def test_array_variable
code = <<~CODE
مصفوفة_الأعداد = [١، ٢]
اطبع(مصفوفة_الأعداد[٠])
CODE

nodes = NodeList.new(
[
SetLocalNode.new('مصفوفة_الأعداد', ArrayNode.new([NumberNode.new(1), NumberNode.new(2)])),
CallNode.new(nil, 'اطبع', [ArrayAccessNode.new(GetLocalNode.new('مصفوفة_الأعداد'), NumberNode.new(0))])
]
)

assert_equal nodes, @parser.parse(code)
end

def test_array_with_newlines
code = <<~CODE
مصفوفة_الأعداد = [
١،
٢
]
اطبع(مصفوفة_الأعداد[٠])
CODE

nodes = NodeList.new(
[
SetLocalNode.new('مصفوفة_الأعداد', ArrayNode.new([NumberNode.new(1), NumberNode.new(2)])),
CallNode.new(nil, 'اطبع', [ArrayAccessNode.new(GetLocalNode.new('مصفوفة_الأعداد'), NumberNode.new(0))])
]
)

assert_equal nodes, @parser.parse(code)
end

def test_nested_arrays
code = <<~CODE
مصفوفة_الأعداد = [
١،
[٢، ٣]
]
اطبع(مصفوفة_الأعداد[١][٠])
CODE

nodes = NodeList.new(
[
SetLocalNode.new('مصفوفة_الأعداد', ArrayNode.new([NumberNode.new(1), ArrayNode.new([NumberNode.new(2), NumberNode.new(3)])])),
CallNode.new(nil, 'اطبع', [ArrayAccessNode.new(ArrayAccessNode.new(GetLocalNode.new('مصفوفة_الأعداد'), NumberNode.new(1)), NumberNode.new(0))])
]
)

assert_equal nodes, @parser.parse(code)
end
end
end

0 comments on commit 52c46c8

Please sign in to comment.