]> git.mdlowis.com Git - proto/sclpl-rb.git/commitdiff
tweaked syntax to get rid of let forms in favor of = for definitions
authorMichael D. Lowis <mike@mdlowis.com>
Mon, 25 May 2020 03:19:03 +0000 (23:19 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Mon, 25 May 2020 03:19:03 +0000 (23:19 -0400)
dyn.rb
dyn.src
runtime [new file with mode: 0644]

diff --git a/dyn.rb b/dyn.rb
index b94d519d2fcd7f954ab1f501f590f1674c2e56cc..beecb497f6798a82246a1886dd415faf178870fb 100755 (executable)
--- a/dyn.rb
+++ b/dyn.rb
@@ -81,8 +81,8 @@ class Lexer
     end
   end
 
-  def linenum(tok = nil)
-    @text[0..(tok.pos || @data.pos)].count("\n") + 1
+  def linenum(pos = nil)
+    @text[0..(pos || @data.pos)].count("\n") + 1
   end
 end
 
@@ -105,25 +105,23 @@ class Parser
   LVLNAMES = LEVELS.keys
 
   RULES = {
-#    "."     => { prefix: nil,         infix: :ufcs_call, level: :call   },
-    "("     => { prefix: :grouping,   infix: :func_call, level: :call   },
-    "+"     => { prefix: :unary,      infix: :binary,    level: :term   },
-    "-"     => { prefix: :unary,      infix: :binary,    level: :term   },
-    "*"     => { prefix: nil,         infix: :binary,    level: :factor },
-    "/"     => { prefix: nil,         infix: :binary,    level: :factor },
-    "="     => { prefix: nil,         infix: :assign,    level: :assign },
-    :let    => { prefix: :definition, infix: nil,        level: :none   },
-    :fun    => { prefix: :function,   infix: nil,        level: :none   },
-    :if     => { prefix: :if_expr,    infix: nil,        level: :none   },
-    :ident  => { prefix: :variable,   infix: nil,        level: :none   },
-    "["     => { prefix: :constant,   infix: :subscript, level: :call   },
-    "{"     => { prefix: :constant,   infix: nil,        level: :none   },
-    :nil    => { prefix: :constant,   infix: nil,        level: :none   },
-    :bool   => { prefix: :constant,   infix: nil,        level: :none   },
-    :num    => { prefix: :constant,   infix: nil,        level: :none   },
-    :string => { prefix: :constant,   infix: nil,        level: :none   },
-    :char   => { prefix: :constant,   infix: nil,        level: :none   },
-    :byte   => { prefix: :constant,   infix: nil,        level: :none   },
+    "("     => { prefix: :grouping,   infix: :func_call,  level: :call   },
+    "+"     => { prefix: :unary,      infix: :binary,     level: :term   },
+    "-"     => { prefix: :unary,      infix: :binary,     level: :term   },
+    "*"     => { prefix: nil,         infix: :binary,     level: :factor },
+    "/"     => { prefix: nil,         infix: :binary,     level: :factor },
+    "="     => { prefix: nil,         infix: :definition, level: :assign },
+    :fun    => { prefix: :function,   infix: nil,         level: :none   },
+    :if     => { prefix: :if_expr,    infix: nil,         level: :none   },
+    :ident  => { prefix: :variable,   infix: nil,         level: :none   },
+    "["     => { prefix: :constant,   infix: :subscript,  level: :call   },
+    "{"     => { prefix: :constant,   infix: nil,         level: :none   },
+    :nil    => { prefix: :constant,   infix: nil,         level: :none   },
+    :bool   => { prefix: :constant,   infix: nil,         level: :none   },
+    :num    => { prefix: :constant,   infix: nil,         level: :none   },
+    :string => { prefix: :constant,   infix: nil,         level: :none   },
+    :char   => { prefix: :constant,   infix: nil,         level: :none   },
+    :byte   => { prefix: :constant,   infix: nil,         level: :none   },
   }
 
   Val = Struct.new(:loc, :type, :value)
@@ -138,24 +136,25 @@ class Parser
     @next = nil
   end
 
+  #######################################
+  # Parsing Rules
+  #######################################
   def toplevel()
-    defs = []
+    defs = {}
     exprs = []
     while !matches(:eof)
       expr = expression()
       if expr.is_a? Def
-        pp expr
+        error("global symbol '#{expr.name}' multiply defined") if defs[expr.name]
+        defs[expr.name] = expr.loc
         exprs << Call.new(expr.loc, :set!, [expr.name, expr.value])
       else
         exprs << expr;
       end
     end
-    exprs
+    [defs, exprs]
   end
 
-  #######################################
-  # Expression Parsing
-  #######################################
   def expression()
     parseLevel(:assign)
   end
@@ -193,24 +192,13 @@ class Parser
     LVLNAMES[index + 1]
   end
 
-  def assign(left)
-    Call.new(location(), :set!, [left, expression()])
-  end
-
   def variable()
     @prev.text.to_sym
   end
 
-  def definition()
+  def definition(name)
     loc = location()
-    name = expect(:ident).text.to_sym
-    expr = nil
-    if (matches("("))
-      expr = function()
-    else
-      expect("=")
-      expr = expression()
-    end
+    expr = expression()
     Def.new(loc, name, expr)
   end
 
@@ -315,8 +303,9 @@ class Parser
   #######################################
   # Parsing Primitives
   #######################################
-  def error(str)
-    puts "#{@lex.file}:#{@lex.linenum(@next || @prev)}: #{str}"
+  def error(str, loc = nil)
+    file, pos = (loc ? loc : [@lex.file, (@next || @prev).pos])
+    puts "#{file}:#{@lex.linenum(pos)}: #{str}"
     exit 1
   end
 
@@ -360,48 +349,85 @@ class Parser
   end
 end
 
-
-module Emit
-  def self.expr(e)
-    if (e.is_a? Parser::Call)
-      Emit.call(e)
-    elsif (e.is_a? Symbol)
-      "#{e}"
-    elsif (e.is_a? String)
-      "MKSTRING(#{e})"
-    elsif (e.is_a? Float)
-      "MKFLOAT(#{e})"
-    else
-      puts e
+class CodeGenerator
+  def initialize(defs, exprs)
+    @syms = Symtable.new
+    @funcs = { toplevel: { freevars: [], code: StringIO.new } }
+    @protos = StringIO.new
+    @protos.print "Value "
+    defs.each do |k,v|
+      @syms[k] = :toplevel
+      @protos.print "#{k}, "
     end
+    @protos.puts "_;"
+    exprs.each {|e| emit(e) }
   end
 
-  def self.string(e)
-    "MKSTR(#{e})"
+  def mkvar()
+    @id = 0 if @id.nil?
+    @id++
+    "_tmp#{@id}"
   end
 
-  def self.call(e)
-    if e.func == :set! then
-      "#{e.args[0]} = #{Emit.expr(e.args[1])};"
-    elsif %w[+ - * /].include?(e.func)
-      "#{Emit.expr(e.args[0])} #{e.func} #{Emit.expr(e.args[1])}"
-    else
-      Emit.calln(e)
+  def emitop(op, left, right = nil)
+    @body << [mkvar, op, left, right]
+    @body.last
+  end
+
+  def func_start(name, args = [])
+    args.each {|a| @syms[a] = :arg }
+    @syms[name] = :func
+    @syms.scope_start
+    @funcs[name.to_sym] = { freevars: [], code: StringIO.new }
+  end
+
+  def func_stop()
+    @syms.scope_stop
+  end
+
+  def dump
+    pp @syms
+    puts @protos.string
+  end
+
+  def emit(e)
+    if e.is_a? Parser::Val
+      emit_val(e)
+    elsif e.is_a? Parser::Def
+      puts "Def"
+    elsif e.is_a? Parser::Call
+      puts "Call"
+    elsif e.is_a? Parser::IfExpr
+      puts "IfExpr"
+    elsif e.is_a? Parser::Func
+      puts "Func"
     end
   end
 
-  def self.calln(e)
-    len = e.args.length
-    args = e.args.map{|a| Emit.expr(a) }.join(", ")
-    if len <= 8
-      "CALL#{len}(#{e.func}, #{args});"
-    else
-      "CALLN(#{e.func}, #{len}, #{args});"
+  def emit_val(e)
+    case e.type
+    when :nil
+      puts "NULL"
+    when :bool
+      puts e.value
+    when :num
+      puts e.value
+    when :string
+      puts e.value
     end
   end
 end
 
-
 parse = Parser.new("dyn.src")
-exprs = parse.toplevel
-pp exprs
+defs, exprs = parse.toplevel
+
+# Print the definition prototypes
+print "Value "
+defs.each {|k,v| print "#{k.to_s}, " }
+puts "_;"
+
+puts exprs
+
+#puts exprs
+#gen = CodeGenerator.new(defs, exprs)
+#gen.dump
diff --git a/dyn.src b/dyn.src
index 4b596af483b10e20a6a6c118092e8d95f3ca24dc..e91d4d0ea32ced0702256cd20fdd4b0f84e8a85f 100644 (file)
--- a/dyn.src
+++ b/dyn.src
@@ -1,35 +1,32 @@
 # constants
-[1,2,3]
-{ "foo": 123 }
 nil
 true
 false
 123
 123.0
 "foo"
-
-# operators
-let a = (456 + 1)
-let a = (456 - 1)
-let a = (456 * 1)
-let a = (456 - 1)
-let a = (-1)
-let a = (+1)
-
-# variables
-let foo = 123
-foo = 42
-
-# conditionals
-if (1)
-  2
-else
-  3
-end
-
-# functions and application
-println("foo!")
-print(1,2,3,4,5,6,7,8,9)
-let foo = fun(a)
+a = 1
+#[1,2,3]
+#{ "foo": 123, 42: 24 }
+#
+## operators
+#a = (456 + 1)
+#b = (456 - 1)
+#c = (456 * 1)
+#d = (456 - 1)
+#e = (-1)
+#f = (+1)
+#
+## conditionals
+#if (1)
+#  2
+#else
+#  3
+#end
+#
+## functions and application
+#println("foo!")
+#print(1,2,3,4,5,6,7,8,9)
+foo1 = fun(a)
   println("hi!")
 end
diff --git a/runtime b/runtime
new file mode 100644 (file)
index 0000000..5a44562
--- /dev/null
+++ b/runtime
@@ -0,0 +1,195 @@
+Generic:
+    apply
+    map
+    foreach
+
+List:
+    list?
+    list
+    list-length
+    list-ref
+    list-append
+    list-map
+    list-foreach
+
+Vector:
+    vector?
+    vector
+    make-vector
+    vector-length
+    vector-ref
+    vector-append
+    vector-map
+    vector-foreach
+
+String:
+    string?
+    string
+    make-string
+    string-length
+    string-ref
+    string-append
+    string-map
+    string-foreach
+
+Map:
+
+Type conversion
+    vector->list
+    list->vector
+    number->string
+    string->number
+    symbol->string
+    string->symbol
+    char->integer
+    integer->char
+    string->list
+    list->string
+
+
+
+
+    pair?
+    cons
+    car
+    cdr
+    set-car!
+    set-cdr!
+    null?
+    append
+    reverse
+    list-tail
+    list-ref
+    memq. memv. member
+    assq
+    assv
+    assoc
+    list->vector
+    vector->list
+    list->string
+    string->list
+    vector->list
+    list->vector
+    string=?
+    string-ci=?
+    substring
+    string->list
+    list->string
+    string-copy
+
+
+
+
+
+
+
+
+
+Equivalence predicates
+    eq?
+    eqv?
+    equal?
+    string=?
+    string-ci=?
+    char=?
+    char-ci=?
+
+
+Strings
+
+Characters
+    char?
+    char=?
+    char-ci=?
+    char<? char-ci<?
+    char<=? char-ci<=?
+    char>? char-ci>?
+    char>=? char-ci>=?
+    char-alphabetic?
+    char-numeric?
+    char-whitespace?
+    char-upper-case?
+    char-lower-case?
+    char->integer
+    integer->char
+    char-upcase
+    char-downcase
+
+Vectors
+
+Symbols
+    symbol->string
+    string->symbol
+    symbol?
+
+Pairs and lists
+    pair?
+    cons
+    car
+    cdr
+    set-car!
+    set-cdr!
+    null?
+    list?
+    list
+    length
+    append
+    reverse
+    list-tail
+    list-ref
+    memq. memv. member
+    assq
+    assv
+    assoc
+    list->vector
+    vector->list
+    list->string
+    string->list
+
+Identity predicates
+    boolean?
+    pair?
+    symbol?
+    number?
+    char?
+    string?
+    vector?
+    port?
+    procedure?
+
+Continuations
+    call-with-current-continuation (call/cc)
+    values
+    call-with-values
+    dynamic-wind
+
+Environments
+    eval
+    scheme-report-environment
+    null-environment
+    interaction-environment (optional)
+
+Input/output
+    display
+    newline
+    read
+    write
+    read-char
+    write-char
+    peek-char
+    char-ready?
+    eof-object? open-input-file
+    open-output-file
+    close-input-port
+    close-output-port
+    input-port?
+    output-port?
+    current-input-port
+    current-output-port
+    call-with-input-file
+    call-with-output-file
+    with-input-from-file(optional)
+    with-output-to-file(optional)
+
+Booleans
+    boolean? not
\ No newline at end of file