Skip to content

Instantly share code, notes, and snippets.

@PedroHLC
Last active October 10, 2017 01:14
Show Gist options
  • Save PedroHLC/33e52bc7ddfe5df4e5e3 to your computer and use it in GitHub Desktop.
Save PedroHLC/33e52bc7ddfe5df4e5e3 to your computer and use it in GitHub Desktop.
A never finished ugly & useless programming language
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
}
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
require_relative 'interpreter.rb'
$log = Uni::Language::Interpreter::Log.new([:error, :warning, :info])
$doc = Uni::Language::Blocks::Document.new('example.uni', $log)
$doc.process
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