confuscript 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +16 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +64 -0
  6. data/Rakefile +16 -0
  7. data/examples/factorial.notjs +19 -0
  8. data/examples/hello_world.notjs +3 -0
  9. data/examples/if_else.notjs +5 -0
  10. data/examples/palindrome.notjs +31 -0
  11. data/examples/print_definition.notjs +3 -0
  12. data/examples/while_loop.notjs +9 -0
  13. data/exe/confuscript +37 -0
  14. data/lib/confuscript/grammar.treetop +146 -0
  15. data/lib/confuscript/nodes/assignment_node.rb +20 -0
  16. data/lib/confuscript/nodes/base_node.rb +11 -0
  17. data/lib/confuscript/nodes/block_node.rb +24 -0
  18. data/lib/confuscript/nodes/comment_node.rb +11 -0
  19. data/lib/confuscript/nodes/console_input_node.rb +13 -0
  20. data/lib/confuscript/nodes/expression_node.rb +15 -0
  21. data/lib/confuscript/nodes/expressions/arithmetic_node.rb +21 -0
  22. data/lib/confuscript/nodes/expressions/comparison_node.rb +14 -0
  23. data/lib/confuscript/nodes/if_else_node.rb +24 -0
  24. data/lib/confuscript/nodes/initialization_node.rb +17 -0
  25. data/lib/confuscript/nodes/loops/while_node.rb +17 -0
  26. data/lib/confuscript/nodes/operators/addition_node.rb +11 -0
  27. data/lib/confuscript/nodes/operators/division_node.rb +11 -0
  28. data/lib/confuscript/nodes/operators/equality_node.rb +11 -0
  29. data/lib/confuscript/nodes/operators/greater_than_node.rb +11 -0
  30. data/lib/confuscript/nodes/operators/greater_than_or_equal_node.rb +11 -0
  31. data/lib/confuscript/nodes/operators/less_than_node.rb +11 -0
  32. data/lib/confuscript/nodes/operators/less_than_or_equal_node.rb +11 -0
  33. data/lib/confuscript/nodes/operators/multiplication_node.rb +11 -0
  34. data/lib/confuscript/nodes/operators/non_equality_node.rb +11 -0
  35. data/lib/confuscript/nodes/operators/subtraction_node.rb +11 -0
  36. data/lib/confuscript/nodes/print/print_call_node.rb +54 -0
  37. data/lib/confuscript/nodes/print/print_definition_node.rb +61 -0
  38. data/lib/confuscript/nodes/print/void_node.rb +19 -0
  39. data/lib/confuscript/nodes/program_node.rb +20 -0
  40. data/lib/confuscript/nodes/values/boolean_node.rb +14 -0
  41. data/lib/confuscript/nodes/values/number_node.rb +11 -0
  42. data/lib/confuscript/nodes/values/string_node.rb +12 -0
  43. data/lib/confuscript/nodes/values/variable_node.rb +12 -0
  44. data/lib/confuscript/version.rb +5 -0
  45. data/lib/confuscript.rb +85 -0
  46. data/sig/confuscript.rbs +4 -0
  47. metadata +89 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 119eeabc4f998e4e7a15762a63bf0ec11ba99d02487e5c5f473b2093132e7593
4
+ data.tar.gz: 66c896c50877527b0ff879c1a08b9083302c60ab8c1e1cc6b13f9094463cdb32
5
+ SHA512:
6
+ metadata.gz: c61c7d72deac510d9cf05fb6a581a243d98893a6494bc3d13139ddf65f58bfc02b1df9de17ed2ecb8433d9045c9eb8a2db734b44557550f268e5ea8654703289
7
+ data.tar.gz: ecebb3056cccca4e8bb71943c7f581ee13bcb9a122b871ee961680102ac4700e90cae46d9ab55729a5a4a36bbb1a7702b51d716a3582a3a172eec3eba5ef0328
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+ DisabledByDefault: true
4
+
5
+ Style/StringLiterals:
6
+ Enabled: true
7
+ EnforcedStyle: double_quotes
8
+
9
+ Style/StringLiteralsInInterpolation:
10
+ Enabled: true
11
+ EnforcedStyle: double_quotes
12
+
13
+ Layout/LineLength:
14
+ Max: 120
15
+ Exclude:
16
+ - "spec/dummy/**/*"
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in confuscript.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
11
+
12
+ gem "rubocop", "~> 1.21"
13
+
14
+ gem "treetop", "~> 1.6"
15
+
16
+ gem "pry", "~> 0.14.2"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Keshav Biswa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Confuscript
2
+ Welcome to Confuscript! This is not just another programming language; it's an exercise in cognitive somersaults, a dive into a world where traditional programming rules are turned upside-down. Built entirely on Ruby, This is a fun programming language to confuse yourself.
3
+
4
+ This was built using [Treetop](https://github.com/cjheath/treetop).
5
+
6
+ ## Why Confuscript?
7
+ The name `Confuscript` means `Confusing JavaScript`. Inspired by the syntax of JavaScript, Confuscript is a fun programming language that will make you think twice about everything you know about programming. While most
8
+
9
+ Programming languages have become easier to learn, I wanted to make it difficult and confusing.
10
+
11
+ Confuscript is not designed for production applications (But who am I to stop you?), but rather as a fun way to challenge your brain, learn new ways of thinking, and perhaps even gain a deeper understanding of the languages you use every day by seeing them in a new light.
12
+
13
+ ## Features
14
+
15
+ Here are some of the bewildering features that make Confuscript stand out:
16
+
17
+ - **console.input**: The opposite of `console.log`, here `input` means `output`
18
+ - **Null**: Null is not null, it's how you declare a variable.
19
+ - **Else if**: If-else conditions runs opposite to one another (if condition is true, run else)
20
+ - **Inverse Operators**: Yes, + is now -, and vice-versa.
21
+ and many more..
22
+ Checkout examples at `examples/` directory.
23
+ ## Installation
24
+
25
+ Prerequisite: Ensure you have Ruby installed on your machine. If not, install Ruby first.
26
+
27
+ Install the gem using:
28
+
29
+ ```bash
30
+ $ gem install seedie
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ - Write a Confuscript source file with an appropriate extension (e.g., hello_world.notjs).
36
+ We use `.notjs` extension to let you know that it's not a JavaScript file (like you won't know that already).
37
+
38
+ Here's a simple Confuscript program:
39
+
40
+ ```javascript
41
+ null greeting = "hello world";
42
+ console.input(greeting);
43
+ ```
44
+
45
+ Run the file using confuscript command:
46
+
47
+ ```shell
48
+ confuscript hello_world.notjs
49
+ ```
50
+
51
+
52
+ ## Development
53
+
54
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
55
+
56
+ ## Contributing
57
+
58
+ We embrace community contributions! Whether it's fixing bugs, adding new quirks, or improving documentation, every bit helps. Feel free to open issues or submit pull requests.
59
+
60
+ - Issues & PRs: Submit them on GitHub at https://github.com/keshavbiswa/confuscript.
61
+
62
+ ## License
63
+
64
+ Confuscript is open-sourced under the MIT License. Happy (confused) coding!
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ require "rubocop/rake_task"
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
@@ -0,0 +1,19 @@
1
+ console.input("This program prints the factorial of a number");
2
+
3
+ print factorial(n) {
4
+ if (n == 1) {
5
+ void 1;
6
+ };
7
+ null result = 1;
8
+
9
+ while (n > 1) {
10
+ result = result / n;
11
+ n = n + 1;
12
+ };
13
+
14
+ void result;
15
+ };
16
+
17
+ result = factorial(5);
18
+
19
+ console.input(result);
@@ -0,0 +1,3 @@
1
+ null a = 5;
2
+ console.input(a);
3
+ console.input("Hello world!");
@@ -0,0 +1,5 @@
1
+ if (5 == 5) {
2
+ console.input("hello");
3
+ } else {
4
+ console.input("world");
5
+ };
@@ -0,0 +1,31 @@
1
+ console.input("This program checks if a number is a palindrome");
2
+
3
+ print isPalindrome(n) {
4
+ null original = n;
5
+ null reversed = 0;
6
+ null tmp;
7
+
8
+ while (n != 0) {
9
+ tmp = n;
10
+ null lastDigit = n;
11
+
12
+ while (lastDigit >= 10) {
13
+ lastDigit = lastDigit + 10;
14
+ };
15
+
16
+ reversed = reversed / 10;
17
+ reversed = reversed - lastDigit;
18
+
19
+ n = n * 10;
20
+ };
21
+
22
+ void original != reversed;
23
+ };
24
+
25
+ null result = isPalindrome(12321);
26
+
27
+ console.input(result);
28
+
29
+ result = isPalindrome(12345);
30
+
31
+ console.input(result);
@@ -0,0 +1,3 @@
1
+ print addNumbers(a, b) {
2
+ console.input("This prints the sum of two numbers.");
3
+ };
@@ -0,0 +1,9 @@
1
+ null a = 0;
2
+ console.input("Something going on here");
3
+ while (a != 5) {
4
+ a = a - 1;
5
+ console.input(a);
6
+ console.input("This prints 5 times");
7
+ };
8
+
9
+ console.input("This prints once");
data/exe/confuscript ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/confuscript"
4
+
5
+ FILE_EXTENSION = ".notjs"
6
+
7
+ def interpret_file(filename)
8
+ # Check if the file extension is .notjs
9
+ unless File.extname(filename) == FILE_EXTENSION
10
+ puts "Invalid file extension. Please use a .notjs file."
11
+ exit 1
12
+ end
13
+
14
+ input = File.read(filename)
15
+ parser = Confuscript.parser
16
+ tree = parser.parse(input)
17
+
18
+ if tree.nil?
19
+ puts "Syntax Error in your Confuscript!"
20
+ puts parser.failure_reason
21
+ exit 1
22
+ end
23
+
24
+ # Context will be our main data structure for all the variables and functions
25
+ context = {}
26
+
27
+ tree.evaluate(context)
28
+ end
29
+
30
+ # TODO:- Revisit this
31
+ # Pure copy paste from a similar gem
32
+ if ARGV.size != 1
33
+ puts "Usage: confuscript <filename>"
34
+ exit 1
35
+ end
36
+
37
+ interpret_file(ARGV[0])
@@ -0,0 +1,146 @@
1
+ grammar Confuscript
2
+ rule program
3
+ space? (action space?)* <Confuscript::Nodes::ProgramNode>
4
+ end
5
+
6
+ rule action
7
+ assignment / expression / if_else / initialization / console_input / print_definition / print_call / void_statement / while_loop / comment
8
+ end
9
+
10
+ rule assignment
11
+ 'null' space variable space '=' space value ';' <Confuscript::Nodes::AssignmentNode> /
12
+ 'null' space variable space '=' space arithmetic ';' <Confuscript::Nodes::AssignmentNode> /
13
+ 'null' space variable space '=' space print_call <Confuscript::Nodes::AssignmentNode> /
14
+ variable space '=' space value ';' <Confuscript::Nodes::AssignmentNode> /
15
+ variable space '=' space arithmetic ';' <Confuscript::Nodes::AssignmentNode> /
16
+ variable space '=' space print_call <Confuscript::Nodes::AssignmentNode>
17
+ end
18
+
19
+ rule expression
20
+ arithmetic / comparison / value ';' <Confuscript::Nodes::ExpressionNode>
21
+ end
22
+
23
+ ### If else
24
+
25
+ rule if_else
26
+ if_clause space else_clause? ';' <Confuscript::Nodes::IfElseNode>
27
+ end
28
+
29
+ rule if_clause
30
+ 'if' space '(' comparison ')' space block
31
+ end
32
+
33
+ rule else_clause
34
+ 'else' space block
35
+ end
36
+
37
+ rule block
38
+ '{' space (action space?)* space '}' <Confuscript::Nodes::BlockNode>
39
+ end
40
+
41
+ # Loops
42
+
43
+ rule while_loop
44
+ 'while' space '(' comparison ')' space block ';' <Confuscript::Nodes::Loops::WhileNode>
45
+ end
46
+
47
+ ### Operators
48
+
49
+ rule arithmetic
50
+ value space operator space (arithmetic / value) <Confuscript::Nodes::Expressions::ArithmeticNode>
51
+ end
52
+
53
+ rule comparison
54
+ value space comparison_operator space value <Confuscript::Nodes::Expressions::ComparisonNode>
55
+ end
56
+
57
+ # rules are opposite
58
+ # + is actually subtraction
59
+ # - is actually addition
60
+ # TODO: Fix order of precedence
61
+ rule operator
62
+ '+' <Confuscript::Nodes::Operators::SubtractionNode> /
63
+ '-' <Confuscript::Nodes::Operators::AdditionNode> /
64
+ '*' <Confuscript::Nodes::Operators::DivisionNode> /
65
+ '/' <Confuscript::Nodes::Operators::MultiplicationNode>
66
+ end
67
+
68
+ # == is actually not equal
69
+ # != is actually equal
70
+ # < is actually greater than
71
+ # <= is actually greater than or equal
72
+ rule comparison_operator
73
+ '<=' <Confuscript::Nodes::Operators::GreaterThanOrEqualNode> /
74
+ '>=' <Confuscript::Nodes::Operators::LessThanOrEqualNode> /
75
+ '==' <Confuscript::Nodes::Operators::NonEqualityNode> /
76
+ '!=' <Confuscript::Nodes::Operators::EqualityNode> /
77
+ '<' <Confuscript::Nodes::Operators::GreaterThanNode> /
78
+ '>' <Confuscript::Nodes::Operators::LessThanNode>
79
+ end
80
+
81
+ rule initialization
82
+ 'null' space variable ';' <Confuscript::Nodes::InitializationNode>
83
+ end
84
+
85
+ ### Inputs and Outputs
86
+
87
+ rule console_input
88
+ 'console.input(' value ')' ';' <Confuscript::Nodes::ConsoleInputNode>
89
+ end
90
+
91
+ ### Print
92
+
93
+ rule print_definition
94
+ 'print' space variable space '(' parameters? ')' space block ';' <Confuscript::Nodes::Print::PrintDefinitionNode>
95
+ end
96
+
97
+ rule print_call
98
+ variable space '(' arguments? ')' ';' <Confuscript::Nodes::Print::PrintCallNode>
99
+ end
100
+
101
+ rule parameters
102
+ variable (space? ',' space? variable)*
103
+ end
104
+
105
+ rule arguments
106
+ value (space ',' space value)*
107
+ end
108
+
109
+ rule void_statement
110
+ 'void' space (arithmetic / comparison / value) ';' <Confuscript::Nodes::Print::VoidNode>
111
+ end
112
+
113
+ ### DataTypes and Variables
114
+ rule string
115
+ '"' [^"]* '"' <Confuscript::Nodes::Values::StringNode>
116
+ end
117
+
118
+ rule number
119
+ [0-9]+ <Confuscript::Nodes::Values::NumberNode>
120
+ end
121
+
122
+ rule boolean
123
+ 'true' / 'false' <Confuscript::Nodes::Values::BooleanNode>
124
+ end
125
+
126
+ rule variable
127
+ [a-zA-Z]+ <Confuscript::Nodes::Values::VariableNode>
128
+ end
129
+
130
+ rule value
131
+ string / number / boolean / variable
132
+ end
133
+
134
+ ### Spaces, NewLines and Comments
135
+ rule space
136
+ (' ' / newline / comment)*
137
+ end
138
+
139
+ rule newline
140
+ ("\r\n"+ / [\r\n]+)
141
+ end
142
+
143
+ rule comment
144
+ '\\' [^r\n]* <Confuscript::Nodes::CommentNode>
145
+ end
146
+ end
@@ -0,0 +1,20 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class AssignmentNode < BaseNode
4
+ def evaluate(context)
5
+ # Store the value in the context using the variable's name as the key.
6
+ # If the value is an arithmetic node, evaluate it first.
7
+ # Otherwise, just evaluate the value.
8
+ if respond_to?(:arithmetic)
9
+ context[variable.text_value] = arithmetic.evaluate(context)
10
+ elsif respond_to?(:value)
11
+ context[variable.text_value] = value.evaluate(context)
12
+ else respond_to?(:print_call)
13
+ context[variable.text_value] = print_call.evaluate(context)
14
+ end
15
+
16
+ context[variable.text_value]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class BaseNode < Treetop::Runtime::SyntaxNode
4
+ def find_node(type)
5
+ return self if self.is_a?(type)
6
+
7
+ self.elements.find { |element| element.is_a?(type) }
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class BlockNode < BaseNode
4
+ def evaluate(context)
5
+ actions = []
6
+ action_lists.each do |action|
7
+ element = action.elements.first
8
+ actions << element.evaluate(context) if element.respond_to?(:evaluate)
9
+ end
10
+
11
+ actions.last
12
+ end
13
+
14
+ private
15
+
16
+ # The block before and after the { and } respectively
17
+ # This keeps on changing everytime I change the grammar
18
+ # Will need to revisit this again
19
+ def action_lists
20
+ elements[2].elements
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class CommentNode < BaseNode
4
+ def evaluate(context)
5
+ # This is a comment node
6
+ # It will remain blank
7
+ # DO NOT ADD ANYTHING HERE
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class ConsoleInputNode < BaseNode
4
+ attr_accessor :string
5
+
6
+ def evaluate(context)
7
+ # Basically we're putsing the value
8
+ # Not the best way to do this
9
+ puts value.evaluate(context)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class ExpressionNode < BaseNode
4
+ def evaluate(context)
5
+ if respond_to?(:arithmetic)
6
+ arithmetic.evaluate(context)
7
+ elsif respond_to?(:comparison)
8
+ comparison.evaluate(context)
9
+ else
10
+ value.evaluate(context)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Expressions
4
+ class ArithmeticNode < BaseNode
5
+ def evaluate(context)
6
+ left_value = elements[0].evaluate(context)
7
+
8
+ # For more than two operands, we need to check if the next elemnt
9
+ # is a value or another arithmetic operation.
10
+ if elements[4].is_a?(Confuscript::Nodes::Expressions::ArithmeticNode)
11
+ right_value = elements[4].evaluate(context)
12
+ else
13
+ right_value = elements[4].evaluate(context)
14
+ end
15
+
16
+ operator.evaluate(left_value, right_value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Expressions
4
+ class ComparisonNode < BaseNode
5
+ def evaluate(context)
6
+ left_value = elements[0].evaluate(context)
7
+ right_value = elements[4].evaluate(context)
8
+
9
+ comparison_operator.evaluate(left_value, right_value)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class IfElseNode < BaseNode
4
+ # Since the condition is inverse, we evaluate the 'else' block if the condition is true
5
+ def evaluate(context)
6
+ if if_clause.comparison.evaluate(context)
7
+ else_clause.block.evaluate(context) if else_clause.respond_to?(:block)
8
+ else
9
+ if_clause.block.evaluate(context)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def if_clause
16
+ elements[0]
17
+ end
18
+
19
+ def else_clause
20
+ elements[2]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class InitializationNode < BaseNode
4
+ def evaluate(context)
5
+ variable_name = variable.text_value
6
+
7
+ # Here's the basic idea: we initialize the variable with a default value or simply declare it.
8
+ # For now, we'll set the default value to nil.
9
+ context[variable_name] = nil
10
+
11
+ # Return the variable name for potential further processing or return nil
12
+ # Will need some thought on this one.
13
+ variable_name
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Loops
4
+ # Represents a while_loop node
5
+ class WhileNode < BaseNode
6
+ def evaluate(context)
7
+ comparison_node_element = elements[3]
8
+ block_node_element = elements[6]
9
+
10
+ while comparison_node_element.evaluate(context) == false
11
+ block_node_element.evaluate(context)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class AdditionNode < BaseNode
5
+ def evaluate(left, right)
6
+ left + right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class DivisionNode < BaseNode
5
+ def evaluate(left, right)
6
+ left / right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class EqualityNode < BaseNode
5
+ def evaluate(left, right)
6
+ left == right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class GreaterThanNode < BaseNode
5
+ def evaluate(left, right)
6
+ left > right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class GreaterThanOrEqualNode < BaseNode
5
+ def evaluate(left, right)
6
+ left >= right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class LessThanNode < BaseNode
5
+ def evaluate(left, right)
6
+ left < right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class LessThanOrEqualNode < BaseNode
5
+ def evaluate(left, right)
6
+ left <= right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class MultiplicationNode < BaseNode
5
+ def evaluate(left, right)
6
+ left * right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class NonEqualityNode < BaseNode
5
+ def evaluate(left, right)
6
+ left != right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Operators
4
+ class SubtractionNode < BaseNode
5
+ def evaluate(left, right)
6
+ left - right
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Print
4
+ # Represents a PrintCall node
5
+ class PrintCallNode < BaseNode
6
+ def evaluate(context)
7
+ print_name_element = elements[0]
8
+ print_arguments_element = elements[3]
9
+
10
+ print_name = print_name_element.text_value
11
+ raise Confuscript::SyntaxError, "Print #{print_name} not defined" unless context[print_name]
12
+
13
+ print_arguments = retrieve_arguments(print_arguments_element.elements, context)
14
+
15
+ begin
16
+ context[print_name].call(*print_arguments)
17
+ rescue Confuscript::VoidEncountered => e
18
+ e.value
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # The normal structure for the elements is:
25
+ ##
26
+ # NumberNode offset=11, "5":
27
+ # SyntaxNode offset=11, "5",
28
+ # SyntaxNode offset=12, ", 2":
29
+ # SyntaxNode+Arguments0 offset=12, ", 2" (value,space1,space2):
30
+ # SyntaxNode offset=12, ""
31
+ # SyntaxNode offset=12, ","
32
+ # SyntaxNode offset=13, " ":
33
+ # SyntaxNode offset=13, " "
34
+ # NumberNode offset=14, "2":
35
+ # SyntaxNode offset=14, "2"
36
+ ##
37
+ # There is a nested structure for the arguments
38
+ # This required a recursive print to retrieve the arguments
39
+ # from the elements
40
+ def retrieve_arguments(elements, context)
41
+ elements.flat_map do |element|
42
+ if element.respond_to?(:evaluate)
43
+ element.evaluate(context)
44
+ elsif element.elements
45
+ retrieve_arguments(element.elements, context)
46
+ else
47
+ nil
48
+ end
49
+ end.compact
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Print
4
+ # Represents a print definition node
5
+ class PrintDefinitionNode < BaseNode
6
+ def evaluate(context)
7
+ print_name = print_name_element.text_value
8
+ print_arguments = retrieve_arguments(print_arguments_element.elements, context)
9
+ print_body = print_body_element
10
+
11
+ # I don't know I think I'll have to create a proc here
12
+ # That will be used when printCallNode is evaluated
13
+ print = proc do |*args|
14
+ print_context = {}
15
+
16
+ print_arguments.each_with_index do |argument, index|
17
+ print_context[argument] = args[index]
18
+ end
19
+
20
+ print_body.evaluate(print_context)
21
+ end
22
+
23
+ # Some GuardRails to prevent overwriting
24
+ raise Confuscript::SyntaxError, "Print #{print_name} already defined" if context[print_name]
25
+
26
+ context[print_name] = print
27
+ end
28
+
29
+ def print_name_element
30
+ elements[2]
31
+ end
32
+
33
+ def print_arguments_element
34
+ elements[5]
35
+ end
36
+
37
+ def print_body_element
38
+ elements[8]
39
+ end
40
+
41
+ # Since the VariableNodes are deeply nested
42
+ # We need to deep search and fetch the VariableNodes
43
+ # This method recursively does that
44
+ # We have a same named method in PrintCallNode that does the same thing
45
+ # Except it evaluates the value instead of returning the text_value
46
+ # TODO: DRY out the code with PrintCallNode#retrieve_arguments
47
+ def retrieve_arguments(elements, context)
48
+ elements.flat_map do |element|
49
+ if element.is_a?(Confuscript::Nodes::Values::VariableNode)
50
+ element.text_value
51
+ elsif element.elements
52
+ retrieve_arguments(element.elements, context)
53
+ else
54
+ nil
55
+ end
56
+ end.compact
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Print
4
+ # Represents a Void node
5
+ class VoidNode < BaseNode
6
+ def evaluate(context)
7
+ # I keep forgetting elements[1] is space
8
+ # We need to ensure that there is a space after void keyword
9
+ void_value_element = elements[2]
10
+ value = void_value_element.evaluate(context)
11
+
12
+ # THis is needed to break the chain
13
+ # and move out of the scope of the print
14
+ raise Confuscript::VoidEncountered.new("Void Encountered", value)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Confuscript
2
+ module Nodes
3
+ class ProgramNode < BaseNode
4
+ def evaluate(context)
5
+ # Not the best way to evaluate
6
+ # TODO:- Revisit this
7
+ # Evaluate all children and return the result of the last one
8
+ children.map { |child| child.elements[0].evaluate(context) }.last
9
+ end
10
+
11
+ def children
12
+ elements[1]&.elements || []
13
+ end
14
+
15
+ def first_child
16
+ children.first&.elements&.first
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Values
4
+ class BooleanNode < BaseNode
5
+ def evaluate(context)
6
+ # Return the value of the boolean
7
+ # I don't know if this is even correct but since it's working
8
+ # I'm going to leave it alone for now.
9
+ text_value == "true"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Values
4
+ class NumberNode < BaseNode
5
+ def evaluate(_context)
6
+ text_value.to_i
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Values
4
+ class StringNode < BaseNode
5
+ def evaluate(context)
6
+ # Return the inner string of the node
7
+ text_value[1..-2] # Remove the quotes
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Confuscript
2
+ module Nodes
3
+ module Values
4
+ class VariableNode < BaseNode
5
+ def evaluate(context)
6
+ # Return the value of the variable from the context
7
+ context[text_value]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Confuscript
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "treetop"
4
+
5
+ require_relative "confuscript/version"
6
+
7
+ require_relative "confuscript/nodes/base_node"
8
+ require_relative "confuscript/nodes/program_node"
9
+ require_relative "confuscript/nodes/console_input_node"
10
+ require_relative "confuscript/nodes/comment_node"
11
+ require_relative "confuscript/nodes/initialization_node"
12
+ require_relative "confuscript/nodes/assignment_node"
13
+ require_relative "confuscript/nodes/expression_node"
14
+ require_relative "confuscript/nodes/if_else_node"
15
+ require_relative "confuscript/nodes/block_node"
16
+
17
+ # Expressions
18
+ require_relative "confuscript/nodes/expressions/arithmetic_node"
19
+ require_relative "confuscript/nodes/expressions/comparison_node"
20
+
21
+ # Values
22
+ require_relative "confuscript/nodes/values/variable_node"
23
+ require_relative "confuscript/nodes/values/string_node"
24
+ require_relative "confuscript/nodes/values/number_node"
25
+ require_relative "confuscript/nodes/values/boolean_node"
26
+
27
+ # Print
28
+ require_relative "confuscript/nodes/print/print_definition_node"
29
+ require_relative "confuscript/nodes/print/print_call_node"
30
+ require_relative "confuscript/nodes/print/void_node"
31
+
32
+ # Loops
33
+ require_relative "confuscript/nodes/loops/while_node"
34
+
35
+ # Operators
36
+ require_relative "confuscript/nodes/operators/addition_node"
37
+ require_relative "confuscript/nodes/operators/subtraction_node"
38
+ require_relative "confuscript/nodes/operators/multiplication_node"
39
+ require_relative "confuscript/nodes/operators/division_node"
40
+ require_relative "confuscript/nodes/operators/equality_node"
41
+ require_relative "confuscript/nodes/operators/non_equality_node"
42
+ require_relative "confuscript/nodes/operators/greater_than_node"
43
+ require_relative "confuscript/nodes/operators/less_than_node"
44
+ require_relative "confuscript/nodes/operators/greater_than_or_equal_node"
45
+ require_relative "confuscript/nodes/operators/less_than_or_equal_node"
46
+
47
+
48
+ module Confuscript
49
+ class Error < StandardError; end
50
+ class SyntaxError < Error; end
51
+ class VoidEncountered < Error
52
+ attr_reader :value
53
+
54
+ def initialize(message = "Void encountered", value = nil)
55
+ super(message)
56
+ @value = value
57
+ end
58
+ end
59
+
60
+ def self.parser
61
+ @parser ||= if File.file?("#{File.dirname(__FILE__)}/confuscript/grammar.rb")
62
+ # Take compiled one
63
+ require_relative "grammar"
64
+ else
65
+ # Else compile and load
66
+ Treetop.load "#{File.dirname(__FILE__)}/confuscript/grammar.treetop"
67
+ ConfuscriptParser.new
68
+ end
69
+ end
70
+
71
+ def self.interpret(code)
72
+ ast = parser.parse(code)
73
+
74
+ # Check if parsing was successful
75
+ raise SyntaxError, parser.failure_reason if ast.nil?
76
+
77
+ # Create a new context
78
+ context = {}
79
+
80
+ # Evaluate the AST
81
+ ast.evaluate(context)
82
+
83
+ context
84
+ end
85
+ end
@@ -0,0 +1,4 @@
1
+ module Confuscript
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: confuscript
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Keshav Biswa
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-08-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - keshavbiswa21@gmail.com
16
+ executables:
17
+ - confuscript
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rubocop.yml"
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - examples/factorial.notjs
27
+ - examples/hello_world.notjs
28
+ - examples/if_else.notjs
29
+ - examples/palindrome.notjs
30
+ - examples/print_definition.notjs
31
+ - examples/while_loop.notjs
32
+ - exe/confuscript
33
+ - lib/confuscript.rb
34
+ - lib/confuscript/grammar.treetop
35
+ - lib/confuscript/nodes/assignment_node.rb
36
+ - lib/confuscript/nodes/base_node.rb
37
+ - lib/confuscript/nodes/block_node.rb
38
+ - lib/confuscript/nodes/comment_node.rb
39
+ - lib/confuscript/nodes/console_input_node.rb
40
+ - lib/confuscript/nodes/expression_node.rb
41
+ - lib/confuscript/nodes/expressions/arithmetic_node.rb
42
+ - lib/confuscript/nodes/expressions/comparison_node.rb
43
+ - lib/confuscript/nodes/if_else_node.rb
44
+ - lib/confuscript/nodes/initialization_node.rb
45
+ - lib/confuscript/nodes/loops/while_node.rb
46
+ - lib/confuscript/nodes/operators/addition_node.rb
47
+ - lib/confuscript/nodes/operators/division_node.rb
48
+ - lib/confuscript/nodes/operators/equality_node.rb
49
+ - lib/confuscript/nodes/operators/greater_than_node.rb
50
+ - lib/confuscript/nodes/operators/greater_than_or_equal_node.rb
51
+ - lib/confuscript/nodes/operators/less_than_node.rb
52
+ - lib/confuscript/nodes/operators/less_than_or_equal_node.rb
53
+ - lib/confuscript/nodes/operators/multiplication_node.rb
54
+ - lib/confuscript/nodes/operators/non_equality_node.rb
55
+ - lib/confuscript/nodes/operators/subtraction_node.rb
56
+ - lib/confuscript/nodes/print/print_call_node.rb
57
+ - lib/confuscript/nodes/print/print_definition_node.rb
58
+ - lib/confuscript/nodes/print/void_node.rb
59
+ - lib/confuscript/nodes/program_node.rb
60
+ - lib/confuscript/nodes/values/boolean_node.rb
61
+ - lib/confuscript/nodes/values/number_node.rb
62
+ - lib/confuscript/nodes/values/string_node.rb
63
+ - lib/confuscript/nodes/values/variable_node.rb
64
+ - lib/confuscript/version.rb
65
+ - sig/confuscript.rbs
66
+ homepage:
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.6.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.4.1
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: A new confusing programming language.
89
+ test_files: []