confuscript 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []