require 'pp'
module Type
- Void = "void"
- Float = "float"
-
- Range = Struct.new(:start, :stop)
- Int = Range.new(-2147483647, 2147483647)
- UInt = Range.new(0, 0xFFFFFFFF)
- Byte = Range.new(0, 0xFF)
- Char = Range.new(0, 0x10FFFF)
-
- Enum = Struct.new(:entries)
- Bool = Enum.new([:true, :false])
-
+ Array = Struct.new(:type, :count)
+ Record = Struct.new(:fields)
Func = Struct.new(:args, :return)
Ptr = Struct.new(:type)
- Array = Struct.new(:type, :count)
+ Int = Struct.new(:min, :max)
+ Real = Struct.new(:bits)
end
-module AST
- Let = Struct.new(:type, :name, :value)
- Apply = Struct.new(:type, :func, :args)
- Value = Struct.new(:type, :value)
- Func = Struct.new(:type, :args, :body)
- Var = Struct.new(:type, :name)
- If = Struct.new(:type, :cond, :then, :else)
- Block = Struct.new(:type, :exprs)
- Array = Struct.new(:items)
-end
-
-module Codegen
- def self.type_to_s(type)
- if type.is_a? Type::Ptr then
- "#{type_to_s(type.type)}*"
- else
- type
- end
- end
-
- def self.genfunc(ast)
- print "#{type_to_s(ast.type.return)} #{ast.name}("
- print (ast.type.args.each_with_index.map do |t,i|
- type_to_s(t) + " " + ast.value.args[i]
- end.join(", "))
- print ") {\n"
- print " #{type_to_s(ast.type.return)} _rv_;\n"
- print " return _rv_;\n}\n\n"
- end
-
- def self.array_type(type)
- if type.is_a? Type::Array then
- array_type(type.type)
- else
- type
- end
- end
-
- def self.array_dims(type)
- if type.is_a? Type::Array then
- "[#{type.count}]" + array_dims(type.type)
- else
- ""
- end
- end
-
- def self.gendef(ast)
- if ast.type.is_a? Type::Func then
- genfunc(ast)
- elsif ast.type.is_a? Type::Array then
- type = array_type(ast.type)
- printf "#{type} #{ast.name}#{array_dims(ast.type)};\n\n"
- else
- printf "#{type_to_s(ast.type)} #{ast.name};\n\n"
- end
- end
+module Ast
+ Val = Struct.new(:type, :value)
end
-#Codegen.gendef(
-# AST::Let.new(Type::Int, "stuff", AST::Value.new(Type::Int, 42)))
-#Codegen.gendef(
-# AST::Let.new(Type::Bool, "stuff", AST::Value.new(Type::Bool, true)))
-#Codegen.gendef(
-# AST::Let.new(Type::Char, "stuff", AST::Value.new(Type::Char, "A")))
-#Codegen.gendef(
-# AST::Let.new(
-# Type::Array.new(Type::Int), "stuff",
-# AST::Value.new(Type::Array.new(Type::Int), "A")))
-#Codegen.gendef(
-# AST::Let.new(
-# Type::Array.new(Type::Int, 42), "stuff",
-# AST::Value.new(Type::Array.new(Type::Int, 42), "A")))
-#Codegen.gendef(
-# AST::Let.new(
-# Type::Array.new(Type::Array.new(Type::Int, 42), 24), "stuff",
-# AST::Value.new(Type::Array.new(Type::Int, 42), "A")))
-#Codegen.gendef(
-# AST::Let.new(
-# Type::Func.new([Type::Ptr.new(Type::Ptr.new(Type::Char))], Type::Int),
-# "main",
-# AST::Func.new(
-# Type::Func.new([Type::Ptr.new(Type::Ptr.new(Type::Char))], Type::Int),
-# ["args"],
-# AST::Value.new(Type::Int, 0)))
-#)
+BuiltinSyms = {
+ "Bool" => {
+ kind: :type,
+ type: Type::Int.new(0, 1)
+ },
+ "true" => {
+ kind: :const,
+ type: "Bool",
+ value: Ast::Val.new("Bool", 1)
+ },
+ "false" => {
+ kind: :const,
+ type: "Bool",
+ value: Ast::Val.new("Bool", 0)
+ },
+ "Char" => {
+ kind: :type,
+ type: Type::Int.new(0, 0x10FFFF)
+ },
+ "Int" => {
+ kind: :type,
+ type: Type::Int.new(-2**63-1, 2**63-1)
+ },
+ "Real" => {
+ kind: :type,
+ type: Type::Real.new(64)
+ },
+ "Byte" => {
+ kind: :type,
+ type: Type::Int.new(0, 255)
+ },
+}
class Lexer
Tok = Struct.new(:text, :file, :pos, :type)
- SPACE = /[ \t\v\n\r]+/
+ SPACE = /([ \t\v\n\r]+|#.*\n)/
IDENT = /[_a-zA-Z][_a-zA-Z0-9]*/
BRACES = /[\(\)\[\]\{\}]/
- OPERATORS = /[*\/=+-]/
+ OPERATORS = /[*\/=+-:\$]/
INTEGER = /[0-9]+/
ID_TYPES = {
- "requires" => :requires,
- "provides" => :provides,
- "let" => :let,
- "var" => :var,
- "fun" => :fun
+ "module" => :module,
+ "imports" => :imports,
+ "is" => :is
}
def initialize(path)
end
def next
- @data.skip(SPACE)
+ while @data.skip(SPACE) do
+ end
if not @data.eos?
- type = nil
+ type = :eof
if @data.scan(IDENT)
type = get_id_type(@data.matched)
+ elsif @data.scan(INTEGER)
+ type = :int
elsif @data.scan(BRACES)
type = @data.matched
elsif @data.scan(OPERATORS)
type = @data.matched
- elsif @data.scan(INTEGER)
- type = :int
- else
- nil
end
Tok.new(@data.matched, @file, @data.pos, type) if type
else
@next = nil
end
- def requires()
- expect(:requires)
+ #######################################
+ # Top Level Forms
+ #######################################
+ def module()
+ expect(:module)
+ expect(:ident).text
+ end
+
+ def imports()
+ expect(:imports)
expect("(")
reqs = []
- while (peek().type != ")")
+ while (!matches(")"))
reqs << expect(:ident).text
+ expect(",") if !matches(")")
end
expect(")")
reqs
end
- def provides()
- expect(:provides)
- expect("{")
- reqs = {}
- while (peek().type != "}")
- declaration(reqs)
- end
- expect("}")
- reqs
- end
-
- def definitions(defs = {})
- while not eof?
- topdef(defs)
- end
- defs
- end
-
- private
-
- def topdef(defs)
- dectype = declaration(defs)
- if dectype == :fun then
- expect("{")
- value = expression()
- expect("}")
- else
- expect("=")
- value = expression()
- end
- pp value
- end
-
- def declaration(syms)
- deftype = peek().type
- if (accept(:fun) || accept(:let))
- name = expect(:ident).text
- if deftype == :fun
- type = Type::Func.new({}, nil)
- expect("(")
- while (peek().type != ")")
- type.args[expect(:ident).text] = type_annotation()
- expect(",") if (peek().type != ")")
- end
- expect(")")
- type.return = type_annotation()
+ def definitions()
+ defs = {}
+ while !matches(:eof)
+ sym = {
+ export: accept("$"),
+ name: expect(:ident).text
+ }
+ error("#{sym[:name]} multiply defined in module") if defs[sym[:name]]
+ if matches(:is)
+ typedef(sym)
+ elsif matches(":")
+ vardef(sym)
+ elsif matches("(")
+ funcdef(sym)
else
- type = type_annotation()
+ error("invalid symbol definition")
end
- syms[name] = { type: type, value: nil }
- else
- error("invalid declaration")
+ defs[sym[:name]] = sym
end
- deftype
+ defs
end
- def type_annotation()
- name = expect(:ident).text
- if accept("[")
- expect("]")
- Type::Array.new(name, -1)
+ #######################################
+ # Type Definitions
+ #######################################
+ def typedef(sym)
+ expect(:is)
+ sym[:kind] = :type
+ sym[:type] = type_specifier()
+ end
+
+ def type_specifier()
+ if matches("[")
+ array_type()
+ elsif matches("{")
+ struct_type()
+ elsif matches("*")
+ pointer_type()
+# elsif matches(:func)
+# func_type()
else
+ name = expect(:ident).text
+ # TODO: check the type exists
name
end
end
- def expression()
- parseLevel(:assign)
+ def array_type()
+ expect("[")
+ count = expect(:int).text.to_i if matches(:int)
+ basetype = type_specifier()
+ expect("]")
+ Type::Array.new(basetype, count)
end
- def getRule(tok)
- RULES[tok.type]
+ def struct_type()
+ struct = Type::Record.new({})
+ expect("{")
+ while !matches("}")
+ name = expect(:ident).text
+ expect(":")
+ type = type_specifier()
+ struct.fields[name] = type
+ end
+ expect("}")
+ struct
end
- def keepGoing(level)
- rule = getRule(peek())
- (LEVELS[level] <= LEVELS[rule[:level]]) if rule
+ def pointer_type()
+ expect("*")
+ Type::Ptr.new(type_specifier())
end
- def parseLevel(level)
- consume()
- prefixRule = getRule(@prev)[:prefix]
- if not prefixRule then
- error("expected an expression")
- end
- ast = send(prefixRule)
- while keepGoing(level)
- consume()
- infixRule = getRule(@prev)[:infix]
- ast = send(infixRule, ast)
+ #######################################
+ # Variable Definitions
+ #######################################
+ def vardef(sym)
+ expect(":")
+ sym[:kind] = :var
+ sym[:type] = type_specifier()
+ if accept("=")
+ sym[:value] = const_expr()
end
- ast
end
- def constant()
- if (@prev.type == :int)
- AST::Value.new(Type::Int, @prev.text.to_i)
- else
- error("not a valid constant")
- end
+ def const_expr()
+ expect("{")
+ expect("}")
end
- def grouping()
- ast = expression()
- expect(")")
- ast
+ #######################################
+ # Function Definitions
+ #######################################
+ def funcdef(sym)
+ sym[:kind] = :func
+ sym[:type] = Type::Func.new([], nil)
+ func_args(sym)
+ sym[:type].return = type_specifier() if accept(":")
+ expect("{")
+ expect("}")
end
- def func_call(ast)
+ def func_args(sym)
+ expect("(")
+ while !matches(")")
+ arg = { name: expect(:ident).text }
+ expect(":")
+ arg[:type] = type_specifier()
+ expect(",") if !matches(")")
+ sym[:type].args << arg
+ end
expect(")")
- AST::Apply.new(nil, ast, [])
end
- def unary()
- type = @prev.type
- AST::Apply.new(nil, @prev.type, [parseLevel(:unary)])
- end
-
- def nextLevel(tok)
- level = getRule(@prev)[:level]
- index = LVLNAMES.find_index(level)
- LVLNAMES[index + 1]
- end
-
- def binary(left)
- type = @prev.type
- nlvl = nextLevel(type)
- right = parseLevel(nlvl)
- AST::Apply.new(nil, type, [left, right])
+ def func_body(sym)
+ expect("{")
+ expect("}")
end
def error(str)
- raise str
+ puts str
+ exit 1
end
def peek()
end
class Package
- def initialize(name)
- @name = name
- @externs = {}
- @provides = {}
+ def initialize(path)
+ @name = nil
+ @imports = {}
+ @declares = {}
@definitions = {}
+ add_file(path)
end
def add_file(path)
parse = Parser.new(path)
- parse.requires
- @provides = parse.provides
- @definitions = parse.definitions
+ @name = parse.module()
+ @imports = parse.imports()
+ @definitions = parse.definitions()
end
def add_files(paths)
end
def dump
- pp @definitions
+ pp({
+ name: @name,
+ imports: @imports,
+ defines: @definitions
+ })
end
end
-pkg = Package.new("example")
-pkg.add_file("example.src")
+pkg = Package.new("example.src")
pkg.dump()