Last active
October 10, 2017 01:14
-
-
Save PedroHLC/33e52bc7ddfe5df4e5e3 to your computer and use it in GitHub Desktop.
A never finished ugly & useless programming language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global var int test | |
module Exemplo { | |
module SubModulo { | |
class OlhaUmaClasse { | |
const var<public> string test = "woohoo" | |
const var<public> vector<vector<int>> test2 = [[5, 6, 7, 8]] | |
const var<protected> double other_test = 80 + 50.5 + (60 * 8 + 7) | |
const var string more_test = "blabla bla ${other_test}" + ", woohoo\n" | |
const var<private> byte example = 0xA3 | |
const var char test = 'c' | |
const var string heredoc_test = <<<HEREDOC | |
LIKE A ROLLING STONE | |
HEREDOC | |
const var hash ooo = { | |
'x' => "TEST", | |
'y' => "OTHER" | |
} | |
const var bool conditioned = (true ? "example" : nil) | |
var<protected> int x1 | |
fn int example_static_function (int x, int y) { | |
return(x+y+$test) | |
} | |
cfn<public> int example_class_function (int x, int y) { | |
@x1 = Renderer.example_static_function(x, y) | |
return(@x1) | |
} | |
deleg int some_delegated_type (int, int) | |
const some_delegated_type some_function = Λsome_delegated_type {|x, y| | |
return(x+y) | |
} | |
!class_init (int val_tox1) { | |
@x1 = val_tox1 | |
} | |
} | |
} | |
} | |
!main { | |
$stdout.puts("Hello World!!!") | |
return 1 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'uni.rb' | |
class MatchData | |
def captures_to_h | |
groups = {} | |
self.names.each do |k| | |
v = self[k] | |
groups[k] = v if v != nil | |
end | |
return groups | |
end | |
end | |
module Uni | |
module Language | |
module Interpreter | |
REGEX_TOKEN_SCANNER = /\#.*\n|\/\*(?:[^\*\\]|\\.)*\*\/|"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|\/(?:[^\/\\\n]|\\.)*\/[gmixXsuUAJ]*|\<{3}(?'end'\w+)\n(?'heredoc'.*)\n\k'end'(?![\w\_\d])|[\w\_]+(?:\:\:[\w\_]+)*\:\:[\w\_]+|[\=\!\>\<\~]\=|[\*\/\^]\=|[\=,\-]\>|(?<![\w\_\d])(?:0[xX](?:[a-fA-F0-9]{2})+|\d*\.\d+\f?)(?![\w\_\d])|(?<!\\)[\\\/\(\)\{\}\[\]\.\=\*\^\-\+\,\;\n]|[\$\@\:]?[\w\_]+|\S/ | |
class CodeToken < String | |
attr_reader :match_pos, :match_captures, :match_linenumber | |
def initialize (value, pos, ln, groups = nil) | |
super(value) | |
@match_pos = pos | |
@match_linenumber = ln | |
@match_captures = groups | |
end | |
end | |
def self.tokenize(str) | |
results = [] | |
ln = 0 | |
str.scan(REGEX_TOKEN_SCANNER) do |occurence| | |
match = Regexp.last_match | |
if match[0] == "\n" | |
ln += 1 | |
next | |
end | |
results << CodeToken.new(match[0], match.offset(0).first, ln, match.captures_to_h) | |
end | |
return results | |
end | |
def self.find_document(levels) | |
levels.reverse_each do |level| | |
return level if level.is_a?(Blocks::Document) | |
end | |
return nil | |
end | |
module LogFlags | |
ALERT = '[ALERT]' | |
INSERTED = '[<]' | |
ERROR = '[ERROR]' | |
end | |
class Log | |
#@allow values => :error :warning :info :flood | |
def initialize (allow=[:error], output=$stdout) | |
@allow = allow | |
@output = output | |
end | |
def log (flag, str, target=:infreverseo) | |
@output.puts (!flag.nil? ? flag+' ' : '')+str if (@allow.include?(target)) | |
return str | |
end | |
end | |
module GenericMsg | |
def self.invalid_token(log, token, level) | |
return log.log(LogFlags::ERROR, | |
'Invalid token '+token.inspect+ | |
' at '+GenericMsg.get_pos(token, level), | |
:error) | |
end | |
def self.get_pos(token, level) | |
document = Interpreter.find_document(level) | |
if(document.nil?) | |
document = :virtual | |
else | |
document = document.filepath.inspect | |
end | |
return 'byte #'+token.match_pos.to_s+' / line #'+token.match_linenumber.to_s+' in document '+document | |
end | |
end | |
end | |
module Operations | |
module Value | |
def self.interpret (log, token_list, ti, level) | |
token = token_list[ti] | |
working = nil | |
loop do | |
break if token.nil? | |
if working.nil? | |
if token == Language::Keywords::END_OF_EXPRESSION | |
raise log.log(Interpreter::LogFlags::ERROR, 'Expressione ended before value was received', :error) | |
elsif token == Language::Keywords::OP_PRIORITY_END | |
raise log.log(Interpreter::LogFlags::ERROR, 'Must have a value before closing paranteses', :error) | |
elsif token == Language::Keywords::OP_PRIORITY_START | |
value, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
working = Operations::Value::Priority.new(value) | |
token = token_list[ti] | |
if token == Language::Keywords::OP_PRIORITY_END | |
token = token_list[ti+=1] | |
else | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
elsif token == Language::Keywords::VECTOR_START | |
working = [] | |
token = token_list[ti+=1] | |
loop do | |
v, ti = Operations::Value.interpret(log, token_list, ti, level) | |
working << v | |
token = token_list[ti] | |
if token == Language::Keywords::VECTOR_END | |
ti+=1 | |
break | |
elsif token == Language::Keywords::VECTOR_SEP | |
ti+=1 | |
next | |
else | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::HASH_START | |
working = {} | |
token = token_list[ti+=1] | |
loop do | |
key, ti = Operations::Value.interpret(log, token_list, ti, level) | |
token = token_list[ti] | |
if token == Language::Keywords::HASH_END | |
working << key | |
ti+=1 | |
break; | |
elsif token == Language::Keywords::HASH_SEP | |
working << key | |
ti+=1 | |
next; | |
elsif token != Language::Keywords::HASH_ASSIGN | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
else | |
ti += 1 | |
end | |
value, ti = Operations::Value.interpret(log, token_list, ti, level) | |
token = token_list[ti] | |
if token == Language::Keywords::HASH_END | |
working[key] = value | |
token = token_list[ti+=1] | |
break | |
elsif token == Language::Keywords::HASH_SEP | |
working[key] = value | |
token = token_list[ti+=1] | |
next | |
else | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::BOOL_TRUE | |
working = true | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::BOOL_FALSE | |
working = false | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::OP_ADD | |
log.log(Interpreter::LogFlags::ALERT, 'Useless operator found at '+ | |
Interpreter::GenericMsg.get_pos(token, level), :warning) | |
token = token_list[ti+=1] | |
next; | |
elsif token == Language::Keywords::OP_MULTIPLY or | |
token == Language::Keywords::OP_DIVIDE or | |
token == Language::Keywords::OP_POWER or | |
token == Language::Keywords::OP_MODULOS | |
raise log.log(Interpreter::LogFlags::ERROR, 'Invalid operator found at '+ | |
Interpreter::GenericMsg.get_pos(token, level), :error) | |
elsif token == Language::Keywords::OP_SUBTRACT | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to negativate', :error) | |
end | |
token = token_list[ti] | |
working = Value::Math.new(nil, :minus, next_val) | |
elsif token[0] == ?' | |
working = Value::Character.new(token[1..-2]) | |
token = token_list[ti+=1] | |
elsif token[0] == ?" | |
working = Value::SimpleString.new(token[1..-2]) | |
token = token_list[ti+=1] | |
# todo interpret concats | |
elsif token[0..2] == "<<<" | |
working = Value::SimpleString.new(token.match_captures['heredoc']) | |
token = token_list[ti+=1] | |
# todo interpret concats | |
elsif (Integer(token) rescue false) | |
working = Integer(token) | |
token = token_list[ti+=1] | |
elsif (Float(token) rescue false) | |
working = Float(token) | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::LAMBDA | |
working, ti = Functions::Lambda.interpret(log, token_list, ti, level) | |
token = token_list[ti] | |
#variavel | |
elsif token == Language::Keywords::REFERENCER | |
token = token_list[ti+=1] | |
working = Value::ReferencedVariable.new(token.to_s) | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::NIL | |
working = Value::PseudoNil.new | |
else | |
working = Value::Variable.new(token.to_s) | |
token = token_list[ti+=1] | |
end | |
else | |
if token == Language::Keywords::OP_PRIORITY_END or token == Language::Keywords::CONDITION_SEP | |
ti -= 1 | |
break; | |
elsif token == Language::Keywords::OP_ADD | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to add', :error) | |
elsif working.is_a?(Value::Concatenated) | |
working.add_back(next_val) | |
elsif next_val.is_a?(Value::Concatenated) | |
working = next_val.add_front(working) | |
elsif working.is_a?(Value::SimpleString) or next_val.is_a?(Value::SimpleString) | |
working = Value::Concatenated.new(working, next_val) | |
elsif working.is_a?(Array) or working.is_a?(Hash) | |
working << next_val | |
elsif next_val.is_a?(Array) or next_val.is_a?(Hash) | |
working = next_val.insert(0, working) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:add, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:add, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :add) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :add, next_val) | |
else | |
# todo custom operator | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}+#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::OP_SUBTRACT | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to subtact', :error) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:subtract, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:subtract, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :subtract) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :subtract, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}-#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::OP_MULTIPLY | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to multiply', :error) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:multiply, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:multiply, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :multiply) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :multiply, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}*#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::OP_DIVIDE | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to divide', :error) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:divide, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:divide, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :divide) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :divide, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}/#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::OP_POWER | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to power', :error) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:power, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:power, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :power) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :power, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}^#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::OP_MODULOS | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to power', :error) | |
elsif working.is_a?(Value::Math) and next_val.is_a?(Value::Math) | |
working.merge(:modulos, next_val) | |
elsif working.is_a?(Value::Math) | |
working.add_after(:modulos, next_val) | |
elsif next_val.is_a?(Value::Math) | |
working = next_val.add_before(working, :modulos) | |
elsif working.is_a?(Fixnum) or next_val.is_a?(Fixnum) or | |
working.is_a?(Float) or next_val.is_a?(Float) or | |
working.is_a?(Value::ReferencedVariable) or next_val.is_a?(Value::ReferencedVariable) or | |
(working.is_a?(Value::Variable) and next_val.is_a?(Value::Variable)) | |
working = Value::Math.new(working, :modulos, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Do not know how to operate this '+"#{working.inspect}%#{next_val.inspect}", :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::VALUE_ASSIGN | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to assign', :error) | |
elsif working.is_a?(Value::Variable) | |
working = Operations::Assignment.new(working, next_val) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Can only assign to variables', :error) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::FUNCTION_PARAM_START | |
params, ti = Value::FunctionCall.interpret(log, token_list, ti, level) | |
working = Value::FunctionCall.new(working, params) | |
if token == Language::Keywords::FUNCTION_PARAM_END | |
token = token_list[ti+=1] | |
else | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
token = token_list[ti] | |
elsif token == Language::Keywords::REL_EQUALS | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:equals, working, next_val) | |
token = token_list[ti] | |
elsif token == Language::Keywords::REL_DIFFERENT | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:different, working, next_val) | |
token = token_list[ti] | |
elsif token == Language::Keywords::REL_GREATER | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:greater, working, next_val) | |
token = token_list[ti] | |
elsif token == Language::Keywords::REL_LESSER | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:lesser, working, next_val) | |
elsif token == Language::Keywords::REL_GREATER_OR_EQUALS | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:greater_equals, working, next_val) | |
token = token_list[ti] | |
elsif token == Language::Keywords::REL_LESSER_OR_EQUALS | |
next_val, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if next_val.nil? | |
raise log.log(Interpreter::LogFlags::ERROR, 'Missing value to compare', :error) | |
end | |
working = Value::Condition.new(:lesser_equals, working, next_val) | |
token = token_list[ti] | |
elsif token == Language::Keywords::CONDITION_SIGN | |
condition = working | |
if working.is_a?(Value::Condition) or working.is_a?(TrueClass) or working.is_a?(FalseClass) or | |
working.is_a?(Value::Variable) or working.is_a?(Value::FunctionCall) | |
elsif working.is_a?(Fixnum) or working.is_a(Float) | |
condition = (token > 0) | |
else | |
raise log.log(Interpreter::LogFlags::ERROR, 'Invalid condition', :error) | |
end | |
iftrueval, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
if token_list[ti] != Language::Keywords::CONDITION_SEP | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
iffalseval, ti = Operations::Value.interpret(log, token_list, ti+1, level) | |
working = Value::Condition.new(condition, iftrueval, iffalseval) | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::END_OF_EXPRESSION | |
break; | |
#forced end_of_expression | |
else | |
ti -= 1 | |
break; | |
end | |
end | |
end | |
return working, ti + 1 | |
end | |
end | |
module Declaration | |
module Variable | |
def self.interpret (log, token_list, ti, level) | |
permission = Language::PERMISSIONS[(level.last.is_a?(Blocks::Class) ? :private : :public)] | |
token = token_list[ti] | |
if token != Language::Keywords::VARIABLE | |
raise @log.log(Interpreter::LogFlags::ERROR, 'Not a variable declaration', :error) | |
end | |
token = token_list[ti+=1] | |
if token == Language::Keywords::SUBTYPE_START | |
token = token_list[ti+=1] | |
if token == Language::Keywords::PERM_PUBLIC or | |
token == Language::Keywords::PERM_PRIVATE or | |
token == Language::Keywords::PERM_PROTECTED | |
case token | |
when Language::Keywords::PERM_PUBLIC | |
permission = Language::PERMISSIONS[:public] | |
when Language::Keywords::PERM_PRIVATE | |
permission = Language::PERMISSIONS[:private] | |
when Language::Keywords::PERM_PROTECTED | |
permission = Language::PERMISSIONS[:protected] | |
end | |
token = token_list[ti+=1] | |
elsif | |
raise @log.log(Interpreter::LogFlags::ERROR, 'Unrecognized variable permission', :error) | |
end | |
if token != Language::Keywords::SUBTYPE_END | |
raise @log.log(Interpreter::LogFlags::ERROR, 'Expecting \'>\' to close variable permission', :error) | |
end | |
token = token_list[ti+=1] | |
end | |
type, ti = TypeInstances.interpret(log, token_list, ti, level) | |
key = token_list[ti] | |
token = token_list[ti+=1] | |
if token == Language::Keywords::VALUE_ASSIGN | |
value, ti = Value.interpret(log, token_list, ti+1, level) | |
return key, type, value, permission, ti | |
else | |
return key, type, nil, permission, ti | |
end | |
end | |
end | |
end | |
module TypeInstances | |
def self.interpret (log, token_list, ti, level) | |
path = token_list[ti].split('::') | |
key = path.pop | |
subtypes = nil | |
token = token_list[ti+=1] | |
if token == Language::Keywords::SUBTYPE_START | |
ti+=1 | |
subtypes = [] | |
loop do | |
type, ti = TypeInstances.interpret(log, token_list, ti, level) | |
subtypes << type | |
token = token_list[ti] | |
if token == Language::Keywords::SUBTYPE_END | |
ti += 1 | |
break | |
elsif token == Language::Keywords::SUBTYPE_SEP | |
ti += 1 | |
next | |
else | |
raise Interpreter::GenericMsg.invalid_token(log, token, level) | |
end | |
end | |
end | |
result = nil | |
native = (path.size < 1 or path == NATIVETYPES_PATH ? Language::NativeTypes.key(key) : nil) | |
if native == nil | |
result = NonNative.new(path, key, subtypes) | |
else | |
result = Native.new(path, key, subtypes, native) | |
end | |
return result, ti | |
end | |
end | |
module Constants | |
def self.interpret (log, token_list, ti, level) | |
token = token_list[ti] | |
if token != Language::Keywords::CONSTANT | |
raise log.log(Interpreter::LogFlags::ERROR, 'Not a constant', :error) | |
end | |
token = token_list[ti+=1] | |
if token == Language::Keywords::VARIABLE | |
key, type, value, permission, ti = Declaration::Variable.interpret(log, token_list, ti, level) | |
if (value.nil?) | |
raise log.log(Interpreter::LogFlags::ERROR, 'Constant variables must have a value', :error) | |
elsif !Constants.is_valid?(value) | |
raise log.log(Interpreter::LogFlags::ERROR, 'Constant variables must have a constant value', :error) | |
end | |
variable = Constants::Variable.new(level.last, key, type, value, permission) | |
level.last.childs << variable | |
log.log(Interpreter::LogFlags::INSERTED, 'Constant variable: '+variable.name, :info) | |
return ti | |
else | |
#todo | |
return ti+1 | |
end | |
end | |
end | |
module GlobalVar | |
def self.interpret (log, token_list, ti, level) | |
token = token_list[ti] | |
if(token != Language::Keywords::GLOBAL_VAR) | |
raise log.log(Interpreter::LogFlags::ERROR, 'Not a global variable', :error) | |
end | |
if(!level.last.is_a?(Blocks::Document)) | |
raise log.log(Interpreter::LogFlags::ERROR, 'Global variable can only be declared in the root scope', :error) | |
end | |
token = token_list[ti+=1] | |
if token == Language::Keywords::VARIABLE | |
key, type, value, permission, ti = Declaration::Variable.interpret(log, token_list, ti, level) | |
variable = GlobalVar::Variable.new(level.last, key, type, value, permission) | |
level.last.childs << variable | |
log.log(Interpreter::LogFlags::INSERTED, 'Global variable: '+variable.name, :info) | |
return ti | |
else | |
#todo | |
return ti+1 | |
end | |
end | |
end | |
end | |
module Blocks | |
class Base | |
def interpret (token_list, ti, level) | |
@childs = [] | |
level << self | |
tl = token_list.size | |
token = token_list[ti] | |
while (ti < tl) | |
#regex failed | |
if token.size <= 0 | |
@log.log(Interpreter::LogFlags::ALERT, 'Corrupted token', :warning) | |
token = token_list[ti+=1] | |
#comment | |
elsif token[0] == ?# | |
@log.log(Interpreter::LogFlags::INSERTED, 'Comment: '+token, :info) | |
token = token_list[ti+=1] | |
next | |
#end of block or file | |
elsif token[0] == ?} || token == nil | |
break; | |
#empty expression | |
elsif token == Language::Keywords::END_OF_EXPRESSION | |
@log.log(Interpreter::LogFlags::INSERTED, 'Useless empty of expression', :flood) | |
token = token_list[ti+=1] | |
#module declaration | |
elsif token == Language::Keywords::MODULE | |
block = Blocks::Module.new(@log) | |
@childs << block | |
ti = block.interpret(token_list, ti, level) | |
token = token_list[ti] | |
#class declaration | |
elsif token == Language::Keywords::CLASS | |
block = Blocks::Class.new(@log) | |
@childs << block | |
ti = block.interpret(token_list, ti, level) | |
token = token_list[ti+=1] | |
elsif token == Language::Keywords::CONSTANT | |
ti = Operations::Constants.interpret(@log, token_list, ti, level) | |
token = token_list[ti] | |
elsif token == Language::Keywords::GLOBAL_VAR | |
ti = Operations::GlobalVar.interpret(@log, token_list, ti, level) | |
token = token_list[ti] | |
elsif token == Language::Keywords::VARIABLE | |
key, type, value, permission, ti = Operations::Declaration::Variable.interpret(@log, token_list, ti, level) | |
variable = Operations::GlobalVar::Variable.new(self, key, type, value, permission) | |
@childs << variable | |
token = token_list[ti] | |
elsif token == Language::Keywords::CLASS_FUNCTION | |
function, ti = Operations::StaticClassFn.interpret(@log, token_list, ti, level) | |
@childs << function | |
token = token_list[ti] | |
elsif token == Language::Keywords::FUNCTION | |
function, ti = Operations::StaticGlobalFn.interpret(@log, token_list, ti, level) | |
@childs << function | |
token = token_list[ti] | |
#macro operation | |
elsif token[0] == ?! | |
macro, ti = Operations::Macro.interpret(@log, token_list, ti, level) | |
@childs << macro | |
token = token_list[ti] | |
#operation | |
else | |
@log.log(Interpreter::LogFlags::ALERT, 'Unprocessed token: '+token, :warning) | |
token = token_list[ti+=1] | |
end | |
end | |
level.pop | |
return ti+1 | |
end | |
end | |
class Document < Base | |
def process | |
return if !File.exists?(@filepath) | |
file = File.new(@filepath, 'rb') | |
self.interpret(Interpreter.tokenize(file.read.to_s), 0, []) | |
end | |
def interpret (token_list, ti, level) | |
@log.log(nil, 'Interpreting file: ' + @filepath) | |
return super(token_list, ti, level) | |
end | |
end | |
class Module < Packaged | |
def interpret (token_list, ti, level) | |
@path_parent = level.last | |
token = token_list[ti] | |
if(token != Language::Keywords::MODULE) | |
raise @log.log(Interpreter::LogFlags::ERROR, 'Not a module', :error) | |
end | |
@name = token_list[ti+=1] | |
@log.log(Interpreter::LogFlags::INSERTED, 'Module: '+get_path(), :info) | |
token = token_list[ti+=1] | |
if token == Language::Keywords::BLOCK_START | |
level << self | |
return super(token_list, ti+1, level) | |
else | |
raise Interpreter::GenericMsg.invalid_token(@log, token, level) | |
end | |
end | |
end | |
class Class < Packaged | |
def interpret (token_list, ti, level) | |
@path_parent = level.last | |
token = token_list[ti] | |
if(token != Language::Keywords::CLASS) | |
raise @log.log(Interpreter::LogFlags::ERROR, 'Not a class', :error) | |
end | |
@name = token_list[ti+=1] | |
@log.log(Interpreter::LogFlags::INSERTED, 'Class: '+get_path(), :info) | |
token = token_list[ti+=1] | |
if token == Language::Keywords::INHERITANCE | |
@type_parent = token_list[ti+=1] | |
token = token_list[ti+=1] | |
end | |
if token == Language::Keywords::BLOCK_START | |
level << self | |
return super(token_list, ti+1, level) | |
else | |
raise Interpreter::GenericMsg.invalid_token(@log, token, level) | |
end | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'interpreter.rb' | |
$log = Uni::Language::Interpreter::Log.new([:error, :warning, :info]) | |
$doc = Uni::Language::Blocks::Document.new('example.uni', $log) | |
$doc.process |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Uni | |
module Language | |
module Keywords | |
MODULE = 'module' | |
MODULE_JOINER = '::' | |
CLASS = 'class' | |
PROP_JOINER = '.' | |
CONSTANT = 'const' | |
GLOBAL_VAR = 'global' | |
VALUE_ASSIGN = '=' | |
VARIABLE = 'var' | |
FUNCTION = 'fn' | |
FUNCTION_PARAM_START = '(' | |
CLASS_FUNCTION = 'cfn' | |
PERM_PUBLIC = 'public' | |
PERM_PRIVATE = 'private' | |
PERM_PROTECTED = 'protected' | |
INHERITANCE = '<' | |
BLOCK_START = '{' | |
BLOCK_END = '}' | |
VECTOR_START = '[' | |
VECTOR_END = ']' | |
VECTOR_SEP = ',' | |
HASH_START = '{' | |
HASH_END = '}' | |
HASH_SEP = ',' | |
HASH_ASSIGN = '=>' | |
SUBTYPE_START = '<' | |
SUBTYPE_END = '>' | |
SUBTYPE_SEP = ',' | |
END_OF_EXPRESSION = ';' | |
REFERENCER = '&' | |
LAMBDA = 'Λ' | |
OP_ADD = '+' | |
OP_SUBTRACT = '-' | |
OP_MULTIPLY = '*' | |
OP_DIVIDE = '/' | |
OP_POWER = '^' | |
OP_MODULOS = '%' | |
OP_PRIORITY_START = '(' | |
OP_PRIORITY_END = ')' | |
REL_EQUALS = '==' | |
REL_DIFFERENT = '!=' | |
REL_GREATER = '>' | |
REL_LESSER = '>' | |
REL_GREATER_OR_EQUALS = '>=' | |
REL_LESSER_OR_EQUALS = '<=' | |
NIL='nil' | |
CONDITION = 'if' | |
CONDITION_SIGN = '?' | |
CONDITION_SEP = ':' | |
MACRO_MAINFN = 'main' | |
BOOL_TRUE = 'true' | |
BOOL_FALSE = 'false' | |
end | |
NativeTypes = { | |
:BOOLEAN => 'bool', | |
:CHARACTER => 'char', | |
:STRING => 'string', | |
:POINTER => 'pointer', | |
:INTEGER_ => 'int', | |
:FLOAT => 'float', | |
:DOUBLE => 'double', | |
:ENUM => 'enum', | |
:STRUCT => 'struct', | |
:VECTOR => 'vector', | |
:ARRAY => 'array', | |
:HASH => 'hash' | |
} | |
NATIVETYPES_PATH = ['Uni', 'NativeTypes']; | |
PERMISSIONS = { | |
:public => 1, | |
:protected => 0, | |
:private => -1 | |
} | |
module Operations | |
class Assignment | |
attr_reader :var_name, :value | |
def initialize(var_name, value) | |
@var_name = var_name | |
@value = value | |
end | |
end | |
module Value | |
class PseudoNil | |
end | |
VALID_MATH = [:add, :subtract, :multiply, :divide, :power, :modulos] | |
class Condition | |
attr_reader :rel_cond, :values | |
def initialize(rel_cond, value1, value2) | |
@rel_cond = rel_cond | |
@values = [value1, value2] | |
end | |
end | |
class Conditioned | |
attr_reader :cond, :values | |
def initialize(cond, value_iftrue, value_iffalse) | |
@cond = cond | |
@values = [value_iftrue, value_iffalse] | |
end | |
end | |
class Concatenated | |
attr_reader :values | |
def initialize(value1, value2) | |
@values = [value1, value2] | |
end | |
def add_front(value) | |
@values.insert(0, value) | |
return self | |
end | |
def add_back(value) | |
@values << value | |
return self | |
end | |
end | |
class Priority | |
attr_reader :value | |
def initialize(value) | |
@value = value | |
end | |
end | |
class Math | |
attr_reader :values | |
def initialize(value1, operation, value2) | |
@values = [value1, operation, value2] | |
end | |
def add_before(value, operation) | |
@values.insert(0, value, operation) | |
return self | |
end | |
def add_after(operation, value) | |
@values << operation | |
@values << value | |
end | |
def merge(operation, value) | |
@values << operation | |
@values += value.values | |
return self | |
end | |
end | |
class Constant | |
attr_reader :type, :value | |
def initialize(type, value) | |
@type = type | |
@value = value | |
end | |
end | |
class FunctionCall | |
attr_reader :key, :params | |
end | |
class SimpleString < String | |
end | |
class Character < String | |
end | |
class Variable | |
def initialize(name) | |
@name = name | |
end | |
end | |
class ReferencedVariable < Variable | |
end | |
end | |
module Declaration | |
module Variable | |
end | |
end | |
module TypeInstances | |
class Base | |
attr_reader :path, :name, :subtypes | |
def initialize(path, name, subtypes=nil) | |
@path = path | |
@name = name | |
@subtypes = subtypes | |
end | |
def validate(cosnt_value) | |
return true | |
end | |
end | |
class NonNative < Base | |
end | |
class Native < Base | |
attr_reader :real_key | |
def initialize(path, name, subtypes=nil, real_key) | |
@real_key = real_key | |
super(path, name, subtypes) | |
end | |
end | |
end | |
module Constants | |
def self.is_valid? (value) | |
if value.is_a?(Value::Constant) or value.is_a?(Value::SimpleString) or value.is_a?(Value::Character) or | |
value.is_a?(Fixnum) or value.is_a?(TrueClass) or value.is_a?(FalseClass) or | |
value.is_a?(Value::PseudoNil) or value.is_a?(Float) | |
return true | |
elsif value.is_a?(Value::Math) | |
value.values.each do |v| | |
if !Value::VALID_MATH.include?(v) and !Constants.is_valid?(v) | |
return false | |
end | |
end | |
return true | |
elsif value.is_a?(Value::Condition) or value.is_a?(Value::Concatenated) | |
value.values.each do |v| | |
return false if !Constants.is_valid?(v) | |
end | |
return true | |
elsif value.is_a?(Value::Conditioned) | |
return false if (!Constants.is_valid?(value.cond)) | |
value.values.each do |v| | |
return false if !Constants.is_valid?(v) | |
end | |
return true | |
elsif value.is_a?(Value::Priority) | |
return (Constants.is_valid?(value.value)) | |
elsif value.is_a?(Hash) or value.is_a?(Array) | |
value.each do |v| | |
return false if !Constants.is_valid?(v) | |
end | |
return true | |
end | |
return false | |
end | |
class Variable | |
attr_reader :path_parent, :name, :type, :value, :permission | |
def initialize(path_parent, name, type, value, permission) | |
@path_parent = path_parent | |
@name = name | |
@type = type | |
@value = value | |
@permission = permission | |
end | |
end | |
end | |
module GlobalVar | |
class Variable | |
attr_reader :path_parent, :name, :type, :value, :permission | |
def initialize(path_parent, name, type, value, permission) | |
@path_parent = path_parent | |
@name = name | |
@type = type | |
@value = value | |
@permission = permission | |
end | |
end | |
end | |
module ClassVar | |
class Variable | |
attr_reader :path_parent, :name, :type, :value, :permission | |
def initialize(path_parent, name, type, value, permission) | |
@path_parent = path_parent | |
@name = name | |
@type = type | |
@value = value | |
@permission = permission | |
end | |
end | |
end | |
end | |
module Blocks | |
class Base | |
attr_reader :childs | |
def initialize (log) | |
@log = log | |
end | |
end | |
class Document < Base | |
attr_reader :filepath | |
def initialize(filepath, log=Interpreter::Log.new) | |
super(log) | |
@filepath = filepath | |
end | |
end | |
class Packaged < Base | |
attr_reader :path_parent, :name | |
def get_path | |
path = [@name] | |
parent = @path_parent | |
while (parent.is_a?(Packaged)) do | |
path << parent.name | |
parent = parent.path_parent | |
end | |
return path.reverse.join(Language::Keywords::MODULE_JOINER) | |
end | |
end | |
class Module < Packaged | |
end | |
class Class < Packaged | |
attr_reader :type_parent | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment