From 7da5e18cc114dda806f11ecf8c2fbd8a2ace6232 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 23 Sep 2014 16:20:39 -0400 Subject: [PATCH] line endings changed --- LICENSE.md | 48 +- README.md | 88 +-- Rakefile | 57 +- docs/lang-reference.lyx | 760 ++++++++++++------------ inc/test-macros.scm | 104 ++-- source/libsof/libsof.h | 84 +-- source/libsof/sof.h | 136 ++--- source/readsof/main.c | 188 +++--- source/slas/main.scm | 44 +- source/slbuild/main.scm | 482 +++++++-------- source/slc/main.scm | 824 +++++++++++++------------- source/slpkg/main.scm | 144 ++--- source/slpkg/server.scm | 88 +-- source/slvm/kernel/parser.h | 54 +- source/slvm/kernel/slvm.c | 1098 +++++++++++++++++------------------ 15 files changed, 2100 insertions(+), 2099 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index da28349..67de0e2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,24 +1,24 @@ - -Copyright (c) 2012, Michael D. Lowis
-All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (c) 2012, Michael D. Lowis
+All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 61f3ee6..27207bd 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,44 @@ -SCLPL -============================================== - - Version: 0.1 - Created By: Michael D. Lowis - Email: mike@mdlowis.com - -About This Project ----------------------------------------------- - -License ----------------------------------------------- -Unless explicitly stated otherwise, all code and documentation contained within -this repository is released under the BSD 2-Clause license. The text for this -license can be found in the LICENSE.md file. - -Requirements For Building ----------------------------------------------- -The only external dependencies currently required to build this library are as -follows: - -* Chciken Scheme -* SConstruct - -Build Instructions ----------------------------------------------- -This project uses SConstruct to build all binaries and libraries. To build the -software simply execute the following command at the root of the project: - - scons - -Project Files and Directories ----------------------------------------------- - - build/ This is the directory where all output files will be placed. - source/ The source for the project. - tests/ Unit test and mock files. - tools/ Tools required by the build system. - Doxyfile Doxygen documentation generator configuration. - LICENSE.md The software license notification. - premake4.lua A premake4 configuration file for generating build scripts. - project.vim A VIM script with project specific configurations. - README.md You're reading this file right now! - +SCLPL +============================================== + + Version: 0.1 + Created By: Michael D. Lowis + Email: mike@mdlowis.com + +About This Project +---------------------------------------------- + +License +---------------------------------------------- +Unless explicitly stated otherwise, all code and documentation contained within +this repository is released under the BSD 2-Clause license. The text for this +license can be found in the LICENSE.md file. + +Requirements For Building +---------------------------------------------- +The only external dependencies currently required to build this library are as +follows: + +* Chciken Scheme +* SConstruct + +Build Instructions +---------------------------------------------- +This project uses SConstruct to build all binaries and libraries. To build the +software simply execute the following command at the root of the project: + + scons + +Project Files and Directories +---------------------------------------------- + + build/ This is the directory where all output files will be placed. + source/ The source for the project. + tests/ Unit test and mock files. + tools/ Tools required by the build system. + Doxyfile Doxygen documentation generator configuration. + LICENSE.md The software license notification. + premake4.lua A premake4 configuration file for generating build scripts. + project.vim A VIM script with project specific configurations. + README.md You're reading this file right now! + diff --git a/Rakefile b/Rakefile index 894833d..9c95398 100644 --- a/Rakefile +++ b/Rakefile @@ -17,30 +17,31 @@ end #------------------------------------------------------------------------------ # Clang Toolchain Targets #------------------------------------------------------------------------------ -CLANG_BUILD_DIR = 'build/llvm' -CLANG_BIN_DIR = 'build/llvm/bin' -CLANG_BIN_NAME = 'clang' -CLANG_SRC_DIR = 'source/vendor/llvm-3.4.2' -CLANG_CMAKE_GENERATOR = ENV['CMAKE_GENERATOR'] || "Unix Makefiles" -CLANG_CMAKE_OPTS = [ '-DCMAKE_BUILD_TYPE=Release' ] -CLANG_MAKE_CMD = windows? ? 'nmake' : 'make' - -file "#{CLANG_BUILD_DIR}/Makefile" => FileList["#{CLANG_SRC_DIR}/cmake/**/*"] do - FileUtils.mkdir_p(CLANG_BUILD_DIR) - FileUtils.cd(CLANG_BUILD_DIR) do - sh "cmake #{CLANG_CMAKE_OPTS.join} -G\"#{CLANG_CMAKE_GENERATOR}\" ../../#{CLANG_SRC_DIR}" - end -end - -file "#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}" => ["#{CLANG_BUILD_DIR}/Makefile"] + FileList["#{CLANG_SRC_DIR}/tools/clang/**/*.c"] do - FileUtils.cd(CLANG_BUILD_DIR) do - sh "#{CLANG_MAKE_CMD} clang" - end -end - -task :clang => ["#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}"] do - ENV['PATH'] = "#{CLANG_BIN_DIR}#{windows? ? ';':':'}#{ENV['PATH']}" -end +#CLANG_BUILD_DIR = 'build/llvm' +#CLANG_BIN_DIR = 'build/llvm/bin' +#CLANG_BIN_NAME = 'clang' +#CLANG_SRC_DIR = 'source/vendor/llvm-3.4.2' +#CLANG_CMAKE_GENERATOR = ENV['CMAKE_GENERATOR'] || "Unix Makefiles" +#CLANG_CMAKE_OPTS = [ '-DCMAKE_BUILD_TYPE=Release' ] +#CLANG_MAKE_CMD = windows? ? 'nmake' : 'make' +# +#file "#{CLANG_BUILD_DIR}/Makefile" => FileList["#{CLANG_SRC_DIR}/cmake/**/*"] do +# FileUtils.mkdir_p(CLANG_BUILD_DIR) +# FileUtils.cd(CLANG_BUILD_DIR) do +# sh "cmake #{CLANG_CMAKE_OPTS.join} -G\"#{CLANG_CMAKE_GENERATOR}\" ../../#{CLANG_SRC_DIR}" +# end +#end +# +#file "#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}" => ["#{CLANG_BUILD_DIR}/Makefile"] + FileList["#{CLANG_SRC_DIR}/tools/clang/**/*.c"] do +# FileUtils.cd(CLANG_BUILD_DIR) do +# sh "#{CLANG_MAKE_CMD} clang" +# end +#end +# +#task :clang => ["#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}"] do +# ENV['PATH'] = "#{CLANG_BIN_DIR}#{windows? ? ';':':'}#{ENV['PATH']}" +#end +task :clang #------------------------------------------------------------------------------ # Envrionment Definitions @@ -63,10 +64,10 @@ at_exit { Environment.process_all } # Define the compiler environment BaseEnv = Environment.new(echo: :command) do |env| env.build_dir('source','build/obj/source') - env['CC'] = 'clang' - env['CXX'] = 'clang' - env['LD'] = 'clang' - env["CFLAGS"] += ['-Wall', '-Wextra' ]#, '-Werror'] +# env['CC'] = 'clang' +# env['CXX'] = 'clang' +# env['LD'] = 'clang' + env["CFLAGS"] += ['--std=gnu99', '-Wall', '-Wextra' ]#, '-Werror'] end #------------------------------------------------------------------------------ diff --git a/docs/lang-reference.lyx b/docs/lang-reference.lyx index e0833f1..6a21797 100644 --- a/docs/lang-reference.lyx +++ b/docs/lang-reference.lyx @@ -1,380 +1,380 @@ -#LyX 2.0 created this file. For more info see http://www.lyx.org/ -\lyxformat 413 -\begin_document -\begin_header -\textclass article -\use_default_options true -\maintain_unincluded_children false -\language english -\language_package default -\inputencoding auto -\fontencoding global -\font_roman default -\font_sans default -\font_typewriter default -\font_default_family default -\use_non_tex_fonts false -\font_sc false -\font_osf false -\font_sf_scale 100 -\font_tt_scale 100 - -\graphics default -\default_output_format default -\output_sync 0 -\bibtex_command default -\index_command default -\paperfontsize default -\spacing single -\use_hyperref false -\papersize letterpaper -\use_geometry true -\use_amsmath 1 -\use_esint 1 -\use_mhchem 1 -\use_mathdots 1 -\cite_engine basic -\use_bibtopic false -\use_indices false -\paperorientation portrait -\suppress_date false -\use_refstyle 1 -\index Index -\shortcut idx -\color #008000 -\end_index -\leftmargin 0.5in -\topmargin 0.5in -\rightmargin 0.5in -\bottommargin 0.5in -\secnumdepth 3 -\tocdepth 3 -\paragraph_separation indent -\paragraph_indentation default -\quotes_language english -\papercolumns 1 -\papersides 1 -\paperpagestyle default -\tracking_changes false -\output_changes false -\html_math_output 0 -\html_css_as_file 0 -\html_be_strict false -\end_header - -\begin_body - -\begin_layout Title -SCLPL - Simple Concurrent List Processing Language -\end_layout - -\begin_layout Author -Michael D. - Lowis -\end_layout - -\begin_layout Date -08/13/13 -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Standard -\begin_inset CommandInset toc -LatexCommand tableofcontents - -\end_inset - - -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Introduction -\end_layout - -\begin_layout Subsection -Rationale -\end_layout - -\begin_layout Subsection -Historical Influences -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Conventions and Semantics -\end_layout - -\begin_layout Subsection -Syntax -\end_layout - -\begin_layout Subsection -Whitepspace and Comments -\end_layout - -\begin_layout Subsection -Identifiers and Naming Conventions -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Core Concepts -\end_layout - -\begin_layout Subsection -Variables and Syntactic Keywords -\end_layout - -\begin_layout Subsection -External Representations -\end_layout - -\begin_layout Subsection -Data Storage Model -\end_layout - -\begin_layout Subsection -Proper Tail Recursion -\end_layout - -\begin_layout Subsection -Immutability -\end_layout - -\begin_layout Subsection -Concurrency Model -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Language Semantics -\end_layout - -\begin_layout Subsection -Expressions -\end_layout - -\begin_layout Subsubsection -Primitive Expressions -\end_layout - -\begin_layout Subsubsection -Literal Expressions -\end_layout - -\begin_layout Subsubsection -Procedure Calls -\end_layout - -\begin_layout Subsubsection -Procedures -\end_layout - -\begin_layout Subsubsection -Conditionals -\end_layout - -\begin_layout Subsubsection -Assignments -\end_layout - -\begin_layout Subsection -Definitions -\end_layout - -\begin_layout Subsection -Syntactic Extensions -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Datatypes and the Type System -\end_layout - -\begin_layout Subsection -Atomic Types -\end_layout - -\begin_layout Subsubsection -Booleans -\end_layout - -\begin_layout Subsubsection -Characters -\end_layout - -\begin_layout Subsubsection -Numbers -\end_layout - -\begin_layout Subsection -Aggregate Types -\end_layout - -\begin_layout Subsubsection -Pairs and Lists -\end_layout - -\begin_layout Subsubsection -Strings -\end_layout - -\begin_layout Subsubsection -Vectors -\end_layout - -\begin_layout Subsubsection -Bytevectors -\end_layout - -\begin_layout Subsubsection -Maps -\end_layout - -\begin_layout Subsubsection -Records -\end_layout - -\begin_layout Subsubsection -Unions -\end_layout - -\begin_layout Subsection -Procedures -\end_layout - -\begin_layout Subsection -Ports -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Input and Output -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Concurrency -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Program Structure -\end_layout - -\begin_layout Subsection -Programs -\end_layout - -\begin_layout Subsection -Import Statements -\end_layout - -\begin_layout Subsection -Definitions -\end_layout - -\begin_layout Subsection -Libraries -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -Standard Library -\end_layout - -\begin_layout Subsection -Procedures -\end_layout - -\begin_layout Subsection -Language Extensions -\end_layout - -\begin_layout Subsubsection -Conditional forms -\end_layout - -\begin_layout Subsubsection -Binding Forms -\end_layout - -\begin_layout Standard -\begin_inset Newpage pagebreak -\end_inset - - -\end_layout - -\begin_layout Section -\start_of_appendix -Formal Syntax -\end_layout - -\begin_layout Section -References -\end_layout - -\end_body -\end_document +#LyX 2.0 created this file. For more info see http://www.lyx.org/ +\lyxformat 413 +\begin_document +\begin_header +\textclass article +\use_default_options true +\maintain_unincluded_children false +\language english +\language_package default +\inputencoding auto +\fontencoding global +\font_roman default +\font_sans default +\font_typewriter default +\font_default_family default +\use_non_tex_fonts false +\font_sc false +\font_osf false +\font_sf_scale 100 +\font_tt_scale 100 + +\graphics default +\default_output_format default +\output_sync 0 +\bibtex_command default +\index_command default +\paperfontsize default +\spacing single +\use_hyperref false +\papersize letterpaper +\use_geometry true +\use_amsmath 1 +\use_esint 1 +\use_mhchem 1 +\use_mathdots 1 +\cite_engine basic +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\use_refstyle 1 +\index Index +\shortcut idx +\color #008000 +\end_index +\leftmargin 0.5in +\topmargin 0.5in +\rightmargin 0.5in +\bottommargin 0.5in +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\paragraph_indentation default +\quotes_language english +\papercolumns 1 +\papersides 1 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Title +SCLPL - Simple Concurrent List Processing Language +\end_layout + +\begin_layout Author +Michael D. + Lowis +\end_layout + +\begin_layout Date +08/13/13 +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset toc +LatexCommand tableofcontents + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Introduction +\end_layout + +\begin_layout Subsection +Rationale +\end_layout + +\begin_layout Subsection +Historical Influences +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Conventions and Semantics +\end_layout + +\begin_layout Subsection +Syntax +\end_layout + +\begin_layout Subsection +Whitepspace and Comments +\end_layout + +\begin_layout Subsection +Identifiers and Naming Conventions +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Core Concepts +\end_layout + +\begin_layout Subsection +Variables and Syntactic Keywords +\end_layout + +\begin_layout Subsection +External Representations +\end_layout + +\begin_layout Subsection +Data Storage Model +\end_layout + +\begin_layout Subsection +Proper Tail Recursion +\end_layout + +\begin_layout Subsection +Immutability +\end_layout + +\begin_layout Subsection +Concurrency Model +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Language Semantics +\end_layout + +\begin_layout Subsection +Expressions +\end_layout + +\begin_layout Subsubsection +Primitive Expressions +\end_layout + +\begin_layout Subsubsection +Literal Expressions +\end_layout + +\begin_layout Subsubsection +Procedure Calls +\end_layout + +\begin_layout Subsubsection +Procedures +\end_layout + +\begin_layout Subsubsection +Conditionals +\end_layout + +\begin_layout Subsubsection +Assignments +\end_layout + +\begin_layout Subsection +Definitions +\end_layout + +\begin_layout Subsection +Syntactic Extensions +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Datatypes and the Type System +\end_layout + +\begin_layout Subsection +Atomic Types +\end_layout + +\begin_layout Subsubsection +Booleans +\end_layout + +\begin_layout Subsubsection +Characters +\end_layout + +\begin_layout Subsubsection +Numbers +\end_layout + +\begin_layout Subsection +Aggregate Types +\end_layout + +\begin_layout Subsubsection +Pairs and Lists +\end_layout + +\begin_layout Subsubsection +Strings +\end_layout + +\begin_layout Subsubsection +Vectors +\end_layout + +\begin_layout Subsubsection +Bytevectors +\end_layout + +\begin_layout Subsubsection +Maps +\end_layout + +\begin_layout Subsubsection +Records +\end_layout + +\begin_layout Subsubsection +Unions +\end_layout + +\begin_layout Subsection +Procedures +\end_layout + +\begin_layout Subsection +Ports +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Input and Output +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Concurrency +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Program Structure +\end_layout + +\begin_layout Subsection +Programs +\end_layout + +\begin_layout Subsection +Import Statements +\end_layout + +\begin_layout Subsection +Definitions +\end_layout + +\begin_layout Subsection +Libraries +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +Standard Library +\end_layout + +\begin_layout Subsection +Procedures +\end_layout + +\begin_layout Subsection +Language Extensions +\end_layout + +\begin_layout Subsubsection +Conditional forms +\end_layout + +\begin_layout Subsubsection +Binding Forms +\end_layout + +\begin_layout Standard +\begin_inset Newpage pagebreak +\end_inset + + +\end_layout + +\begin_layout Section +\start_of_appendix +Formal Syntax +\end_layout + +\begin_layout Section +References +\end_layout + +\end_body +\end_document diff --git a/inc/test-macros.scm b/inc/test-macros.scm index 9bd340d..d557870 100644 --- a/inc/test-macros.scm +++ b/inc/test-macros.scm @@ -1,52 +1,52 @@ - -(define-syntax def-test - (syntax-rules () - ((_ desc body ...) - (register-test! - (cons desc - (lambda () body ...)))))) - -(define-syntax check-error - (syntax-rules () - ((_ expect expr) - (let ((prev error)) - (define result - (call/cc - (lambda (err) - (set! error err) - expr))) - (set! error prev) - (equal? expect result))))) - -(define-syntax check-exception - (syntax-rules () - ((_ expect expr) - (equal? expect - (call/cc - (lambda (cont) - (with-exception-handler - (lambda (x) (cont x)) - (lambda () expr)))))))) - -(define-syntax check-parse-error - (syntax-rules () - ((_ expect expr) - (begin - (define etyp-matches? #f) - (define emsg - (with-output-to-string - (lambda () - (set! etyp-matches? - (equal? 'parse-error - (call/cc - (lambda (cont) - (with-exception-handler - (lambda (x) (cont x)) - (lambda () expr))))))))) - ;(print "----") - ;(print etyp-matches? " " (equal? emsg expect)) - ;(print "\"" emsg "\"\n") - ;(print "\"" expect "\"\n") - ;(print "----") - (and etyp-matches? (equal? emsg expect)))))) - + +(define-syntax def-test + (syntax-rules () + ((_ desc body ...) + (register-test! + (cons desc + (lambda () body ...)))))) + +(define-syntax check-error + (syntax-rules () + ((_ expect expr) + (let ((prev error)) + (define result + (call/cc + (lambda (err) + (set! error err) + expr))) + (set! error prev) + (equal? expect result))))) + +(define-syntax check-exception + (syntax-rules () + ((_ expect expr) + (equal? expect + (call/cc + (lambda (cont) + (with-exception-handler + (lambda (x) (cont x)) + (lambda () expr)))))))) + +(define-syntax check-parse-error + (syntax-rules () + ((_ expect expr) + (begin + (define etyp-matches? #f) + (define emsg + (with-output-to-string + (lambda () + (set! etyp-matches? + (equal? 'parse-error + (call/cc + (lambda (cont) + (with-exception-handler + (lambda (x) (cont x)) + (lambda () expr))))))))) + ;(print "----") + ;(print etyp-matches? " " (equal? emsg expect)) + ;(print "\"" emsg "\"\n") + ;(print "\"" expect "\"\n") + ;(print "----") + (and etyp-matches? (equal? emsg expect)))))) + diff --git a/source/libsof/libsof.h b/source/libsof/libsof.h index cb20bcd..4e9489f 100644 --- a/source/libsof/libsof.h +++ b/source/libsof/libsof.h @@ -1,42 +1,42 @@ -/** - @file libsof.h - @brief TODO: Describe this file - $Revision$ - $HeadURL$ - */ -#ifndef LIBSOF_H -#define LIBSOF_H - -#include "sof.h" -#include -#include -#include - -typedef struct { - sof_header_t* header; - sof_st_entry_t* symbols; - char* strings; - uint8_t* data; - uint32_t* code; -} sof_file_t; - -sof_file_t* libsof_read_obj(char const* fname); -bool libsof_write_obj(sof_file_t* obj, char const* fname); -sof_file_t* libsof_new_obj(void); -void libsof_free_obj(sof_file_t* obj); -size_t libsof_get_symbol_table_size(sof_file_t* obj); -size_t libsof_get_string_table_size(sof_file_t* obj); -size_t libsof_get_data_segment_size(sof_file_t* obj); -size_t libsof_get_code_segment_size(sof_file_t* obj); -size_t libsof_get_num_symbols(sof_file_t* obj); -size_t libsof_add_symbol(sof_file_t* obj, const char* name, uint32_t value, uint32_t size, uint32_t info); -size_t libsof_add_st_entry(sof_file_t* obj, uint32_t name, uint32_t value, uint32_t size, uint32_t info); -sof_st_entry_t const* libsof_get_st_entry(sof_file_t* obj, size_t offset); -size_t libsof_add_string(sof_file_t* obj, char const* name); -char const* libsof_get_string(sof_file_t* obj, size_t offset); -size_t libsof_add_data(sof_file_t* obj, uint8_t const* data, size_t length); -uint8_t const* libsof_get_data(sof_file_t* obj, size_t offset); -size_t libsof_add_code(sof_file_t* obj, uint32_t const* code, size_t length); -uint32_t const* libsof_get_code(sof_file_t* obj, size_t offset); - -#endif /* LIBSOF_H */ +/** + @file libsof.h + @brief TODO: Describe this file + $Revision$ + $HeadURL$ + */ +#ifndef LIBSOF_H +#define LIBSOF_H + +#include "sof.h" +#include +#include +#include + +typedef struct { + sof_header_t* header; + sof_st_entry_t* symbols; + char* strings; + uint8_t* data; + uint32_t* code; +} sof_file_t; + +sof_file_t* libsof_read_obj(char const* fname); +bool libsof_write_obj(sof_file_t* obj, char const* fname); +sof_file_t* libsof_new_obj(void); +void libsof_free_obj(sof_file_t* obj); +size_t libsof_get_symbol_table_size(sof_file_t* obj); +size_t libsof_get_string_table_size(sof_file_t* obj); +size_t libsof_get_data_segment_size(sof_file_t* obj); +size_t libsof_get_code_segment_size(sof_file_t* obj); +size_t libsof_get_num_symbols(sof_file_t* obj); +size_t libsof_add_symbol(sof_file_t* obj, const char* name, uint32_t value, uint32_t size, uint32_t info); +size_t libsof_add_st_entry(sof_file_t* obj, uint32_t name, uint32_t value, uint32_t size, uint32_t info); +sof_st_entry_t const* libsof_get_st_entry(sof_file_t* obj, size_t offset); +size_t libsof_add_string(sof_file_t* obj, char const* name); +char const* libsof_get_string(sof_file_t* obj, size_t offset); +size_t libsof_add_data(sof_file_t* obj, uint8_t const* data, size_t length); +uint8_t const* libsof_get_data(sof_file_t* obj, size_t offset); +size_t libsof_add_code(sof_file_t* obj, uint32_t const* code, size_t length); +uint32_t const* libsof_get_code(sof_file_t* obj, size_t offset); + +#endif /* LIBSOF_H */ diff --git a/source/libsof/sof.h b/source/libsof/sof.h index 6a93b02..cf82684 100644 --- a/source/libsof/sof.h +++ b/source/libsof/sof.h @@ -1,68 +1,68 @@ -/** - @file sof.h - @brief TODO: Describe this file - $Revision$ - $HeadURL$ - */ -#ifndef SOF_H -#define SOF_H - -#include - -/* - SCLPL Object File Layout - - ----------------------- - | SOF Header | - ----------------------- - | Symbol Table | - ----------------------- - | Symbol String Table | - ----------------------- - | Data Segment | - ----------------------- - | Code Segment | - ----------------------- - -*/ - -/* Macro for generating a 32-bit date code based on year, month, and day */ -#define DATE_CODE(year,month,day) (year << 16) | (month << 8) | (day) - -/* The version of the SOF format supported by this library represented as a - * 32-bit date code */ -#define SOF_VERSION DATE_CODE(2013,9,10) - -/* Definition of the SOF file header. The header appears at the beginning of any - * SOF file and contains information about the SOF version of the file and the - * sizes of each section in the file. */ -typedef struct { - /* 32-bit date code representing the version of SOF format used by the file */ - uint32_t version; - /* This size of the symbol table in bytes. A value of 0 indicates that the - * symbol table segment has been omitted from the file */ - uint32_t sym_tbl_sz; - /* The size of the symbol string table segment in bytes. Each entry in the - * symbol string table consists of an array of bytes terminated by a NULL - * byte (0x00). */ - uint32_t sym_str_tbl_sz; - /* The size in bytes of the constant data segment. This segment contains - * constant data that is referenced by the code segment. */ - uint32_t data_sz; - /* The size of the code segment in bytes. Each instruction is represented by - * a 32-bit value and represents a single action to be performed by the - * bytecode interpreter. */ - uint32_t code_sz; -} sof_header_t; - -/* Definition of the SOF symbol table entry */ -typedef struct { - /* Offset into the string section where the string for the symbol is - * located */ - uint32_t name; - uint32_t value; - uint32_t size; - uint32_t info; -} sof_st_entry_t; - -#endif /* SOF_H */ +/** + @file sof.h + @brief TODO: Describe this file + $Revision$ + $HeadURL$ + */ +#ifndef SOF_H +#define SOF_H + +#include + +/* + SCLPL Object File Layout + + ----------------------- + | SOF Header | + ----------------------- + | Symbol Table | + ----------------------- + | Symbol String Table | + ----------------------- + | Data Segment | + ----------------------- + | Code Segment | + ----------------------- + +*/ + +/* Macro for generating a 32-bit date code based on year, month, and day */ +#define DATE_CODE(year,month,day) (year << 16) | (month << 8) | (day) + +/* The version of the SOF format supported by this library represented as a + * 32-bit date code */ +#define SOF_VERSION DATE_CODE(2013,9,10) + +/* Definition of the SOF file header. The header appears at the beginning of any + * SOF file and contains information about the SOF version of the file and the + * sizes of each section in the file. */ +typedef struct { + /* 32-bit date code representing the version of SOF format used by the file */ + uint32_t version; + /* This size of the symbol table in bytes. A value of 0 indicates that the + * symbol table segment has been omitted from the file */ + uint32_t sym_tbl_sz; + /* The size of the symbol string table segment in bytes. Each entry in the + * symbol string table consists of an array of bytes terminated by a NULL + * byte (0x00). */ + uint32_t sym_str_tbl_sz; + /* The size in bytes of the constant data segment. This segment contains + * constant data that is referenced by the code segment. */ + uint32_t data_sz; + /* The size of the code segment in bytes. Each instruction is represented by + * a 32-bit value and represents a single action to be performed by the + * bytecode interpreter. */ + uint32_t code_sz; +} sof_header_t; + +/* Definition of the SOF symbol table entry */ +typedef struct { + /* Offset into the string section where the string for the symbol is + * located */ + uint32_t name; + uint32_t value; + uint32_t size; + uint32_t info; +} sof_st_entry_t; + +#endif /* SOF_H */ diff --git a/source/readsof/main.c b/source/readsof/main.c index 77c6c0e..d7a9d17 100644 --- a/source/readsof/main.c +++ b/source/readsof/main.c @@ -1,94 +1,94 @@ -#include -#include - -#define GET_VERSION_YEAR(version) (version >> 16) -#define GET_VERSION_MONTH(version) ((version >> 8) & 0xFF) -#define GET_VERSION_DAY(version) (version & 0xFF) - -void print_obj(sof_file_t* obj); -void print_hex(char const* header, uint8_t const* buffer, size_t length); - -void create_obj_file(char* fname) -{ - sof_file_t* obj = libsof_new_obj(); - - libsof_add_symbol(obj, "foo", 0x11223344, 0x22222222, 0x33333333); - - uint8_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - libsof_add_data(obj, data, 16); - libsof_add_data(obj, data, 16); - libsof_add_data(obj, data, 16); - - uint32_t code[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - libsof_add_code(obj, code, 16); - libsof_add_code(obj, code, 16); - libsof_add_code(obj, code, 16); - - libsof_write_obj(obj,fname); - libsof_free_obj(obj); -} - -void print_obj(sof_file_t* obj) -{ - /* print header metadata */ - printf("SOF Version:\t%#x (%d/%d/%d)\n", - obj->header->version, - GET_VERSION_DAY(obj->header->version), - GET_VERSION_MONTH(obj->header->version), - GET_VERSION_YEAR(obj->header->version)); - printf("Symbol Table:\t%d bytes\n", obj->header->sym_tbl_sz); - printf("String Table:\t%d bytes\n", obj->header->sym_str_tbl_sz); - printf("Data Size:\t%d bytes\n", obj->header->data_sz); - printf("Code Size:\t%d bytes\n", obj->header->code_sz); - - /* print symbol table */ - printf("\nIndex\tValue\t\tSize\t\tInfo\t\tName\n"); - for(size_t i = 0; i < libsof_get_num_symbols(obj); i++) - { - sof_st_entry_t const* symbol = libsof_get_st_entry(obj,i); - char const* name = libsof_get_string(obj,symbol->name); - printf("[%d]\t%#x\t%#x\t%#x\t%s\n", i, symbol->value, symbol->size, symbol->info, name); - } - - /* print segments as hex listing */ - print_hex("Data Segment", (uint8_t const *)libsof_get_data(obj,0), libsof_get_data_segment_size(obj)); - print_hex("Code Segment", (uint8_t const *)libsof_get_code(obj,0), libsof_get_code_segment_size(obj)); -} - -void print_hex(char const* header, uint8_t const* buffer, size_t length) -{ - printf("\n\n%s\n",header); - printf("----------------------------------------------------------"); - for(size_t i = 0; i < length; i++) - { - if ((i%16) == 0) - { - printf("\n0x%04x\t", i); - } - else if ((i%4) == 0) - { - printf(" "); - } - printf("%02x ", buffer[i]); - } -} - -int main(int argc, char** argv) -{ - if (argc == 1) - { - printf("%s: no input files.\n", argv[0]); - } - else - { - create_obj_file(argv[1]); - for (uint32_t i = 1; i < argc; i++) - { - printf("\nFilename:\t%s\n", argv[i]); - sof_file_t* obj = libsof_read_obj(argv[i]); - print_obj(obj); - libsof_free_obj(obj); - } - } -} - +#include +#include + +#define GET_VERSION_YEAR(version) (version >> 16) +#define GET_VERSION_MONTH(version) ((version >> 8) & 0xFF) +#define GET_VERSION_DAY(version) (version & 0xFF) + +void print_obj(sof_file_t* obj); +void print_hex(char const* header, uint8_t const* buffer, size_t length); + +void create_obj_file(char* fname) +{ + sof_file_t* obj = libsof_new_obj(); + + libsof_add_symbol(obj, "foo", 0x11223344, 0x22222222, 0x33333333); + + uint8_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + libsof_add_data(obj, data, 16); + libsof_add_data(obj, data, 16); + libsof_add_data(obj, data, 16); + + uint32_t code[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + libsof_add_code(obj, code, 16); + libsof_add_code(obj, code, 16); + libsof_add_code(obj, code, 16); + + libsof_write_obj(obj,fname); + libsof_free_obj(obj); +} + +void print_obj(sof_file_t* obj) +{ + /* print header metadata */ + printf("SOF Version:\t%#x (%d/%d/%d)\n", + obj->header->version, + GET_VERSION_DAY(obj->header->version), + GET_VERSION_MONTH(obj->header->version), + GET_VERSION_YEAR(obj->header->version)); + printf("Symbol Table:\t%d bytes\n", obj->header->sym_tbl_sz); + printf("String Table:\t%d bytes\n", obj->header->sym_str_tbl_sz); + printf("Data Size:\t%d bytes\n", obj->header->data_sz); + printf("Code Size:\t%d bytes\n", obj->header->code_sz); + + /* print symbol table */ + printf("\nIndex\tValue\t\tSize\t\tInfo\t\tName\n"); + for(size_t i = 0; i < libsof_get_num_symbols(obj); i++) + { + sof_st_entry_t const* symbol = libsof_get_st_entry(obj,i); + char const* name = libsof_get_string(obj,symbol->name); + printf("[%d]\t%#x\t%#x\t%#x\t%s\n", i, symbol->value, symbol->size, symbol->info, name); + } + + /* print segments as hex listing */ + print_hex("Data Segment", (uint8_t const *)libsof_get_data(obj,0), libsof_get_data_segment_size(obj)); + print_hex("Code Segment", (uint8_t const *)libsof_get_code(obj,0), libsof_get_code_segment_size(obj)); +} + +void print_hex(char const* header, uint8_t const* buffer, size_t length) +{ + printf("\n\n%s\n",header); + printf("----------------------------------------------------------"); + for(size_t i = 0; i < length; i++) + { + if ((i%16) == 0) + { + printf("\n0x%04x\t", i); + } + else if ((i%4) == 0) + { + printf(" "); + } + printf("%02x ", buffer[i]); + } +} + +int main(int argc, char** argv) +{ + if (argc == 1) + { + printf("%s: no input files.\n", argv[0]); + } + else + { + create_obj_file(argv[1]); + for (uint32_t i = 1; i < argc; i++) + { + printf("\nFilename:\t%s\n", argv[i]); + sof_file_t* obj = libsof_read_obj(argv[i]); + print_obj(obj); + libsof_free_obj(obj); + } + } +} + diff --git a/source/slas/main.scm b/source/slas/main.scm index bf7d6f2..5c98197 100644 --- a/source/slas/main.scm +++ b/source/slas/main.scm @@ -1,22 +1,22 @@ -(declare (uses library)) - -(define usage -"\nUsage: slas - -Assemble to SCLPL bytecode and write the result to .\n") - -; Control Routines -;------------------------------------------------------------------------------ -(define (assemble-file infile outfile) - (define iprt (open-input-file infile)) - (define oprt (open-output-file outfile)) - (generate-bytecode iprt oprt)) - -(define (generate-bytecode iprt oprt) '()) - -; Main routine -;------------------------------------------------------------------------------ -(if (= 2 (length (command-line-arguments))) - (apply assemble-file (command-line-arguments)) - (print usage)) -(exit) +(declare (uses library)) + +(define usage +"\nUsage: slas + +Assemble to SCLPL bytecode and write the result to .\n") + +; Control Routines +;------------------------------------------------------------------------------ +(define (assemble-file infile outfile) + (define iprt (open-input-file infile)) + (define oprt (open-output-file outfile)) + (generate-bytecode iprt oprt)) + +(define (generate-bytecode iprt oprt) '()) + +; Main routine +;------------------------------------------------------------------------------ +(if (= 2 (length (command-line-arguments))) + (apply assemble-file (command-line-arguments)) + (print usage)) +(exit) diff --git a/source/slbuild/main.scm b/source/slbuild/main.scm index faa7e5e..00766c8 100644 --- a/source/slbuild/main.scm +++ b/source/slbuild/main.scm @@ -1,241 +1,241 @@ -(declare (uses posix)) -(use posix) - -; Task Definition and Interaction -;------------------------------------------------------------------------------ -(define-record task name desc active? deps actions) - -(define top-level-tasks '()) - -(define current-namespace - (make-parameter '())) - -(define current-desc - (make-parameter #f)) - -(define (task-register! task) - (define name (task-name task)) - (define entry (assoc name top-level-tasks)) - (if (not entry) - (set! top-level-tasks (cons (cons name task) top-level-tasks)) - (set-cdr! entry (task-merge (cdr entry) task)))) - -(define (task-merge task1 task2) - (make-task (task-name task1) (task-desc task1) #t - (append (task-deps task1) - (task-deps task2)) - (append (task-actions task1) - (task-actions task2)))) - -(define (task-lookup name) - (define entry (assoc name top-level-tasks)) - (if (not entry) - (error (string-append "No such task: " name)) - (cdr entry))) - -(define (task-invoke! name) - (define task (task-lookup name)) - (if (task-active? task) - (begin (task-active?-set! task #f) - (map task-invoke! (task-deps task)) - (map (lambda (fn) (fn)) (task-actions task))))) - -(define (gen-task-name name) - (define namespace (current-namespace)) - (if (not (null? namespace)) - (string-append namespace ":" name) - name)) - -; Environment Functions -;------------------------------------------------------------------------------ -(define-record builder defaults action) - -(define (get-sys-env) - (get-environment-variables)) - -(define (set-sys-env! newenv) - (clear-sys-env!) - (map (lambda (p) (setenv (car p) (cdr p))) - newenv)) - -(define (clear-sys-env!) - (map (lambda (p) (unsetenv (car p))) - (get-environment-variables))) - -(define current-env - (let [(curr-env (get-sys-env))] - (lambda args - (if (> (length args) 0) - (begin (set-sys-env! (car args)) - (set! curr-env (car args))) - curr-env)))) - -(define (env-clone env . vars) - (define newenv (map (lambda (p) (cons (car p) (cdr p))) env)) - (define newvals '()) - (map (lambda (e) - (define entry (assoc (car e) newenv)) - (if entry - (set-cdr! entry (cdr e)) - (set! newvals (cons e newvals)))) - vars) - (append newvals newenv)) - -(define (env-get env key) - (define entry (assoc key env)) - (if entry (cdr entry) #f)) - -(define (env-set env key value) - (cons (cons key value) - (env-unset env key))) - -(define (env-unset env key) - (cond [(null? env) '()] - [(string=? (caar env) key) (env-unset (cdr env) key)] - [else (cons (car env) (env-unset (cdr env) key))])) - -(define (env-extend env . vars) - (foldl (lambda (env p) - (env-set env (car p) (cdr p))) - env - vars)) - -(define (env-substitute env str) - (list->string (sub-vars (string->list str) env))) - -(define (env-prepend-path env path) - '()) - -(define (env-append-path env path) - '()) - -(define (env-add-builders env . builders) - '()) - -; Builders -;------------------------------------------------------------------------------ - - -; System Utility Functions -;------------------------------------------------------------------------------ -(define verbose #f) - -(define (build type . args) - (define bldr (assoc type (assoc "builders" (current-env)))) - (define bldr-env (env-merge (builder-defaults bldr) (current-env))) - (apply (builder-action bldr) (cons bldr-env args))) - -(define (run . args) - (define cmd (env-substitute (current-env) (string-join args " "))) - (if verbose (print cmd)) - (if (not (= 0 (system cmd))) - (fail-build cmd))) - -(define (fail-build cmd) - (print "Error: Command returned a non-zero status") - (exit 1)) - -; Directories -(define cd change-directory) -(define curdir current-directory) -(define mkdir create-directory) -(define rmdir delete-directory) -(define lsdir directory) -(define dir? directory?) -; glob - -; Files -(define cp '()) -(define mv '()) -(define rm delete-file) - -; String Templating -;------------------------------------------------------------------------------ -(define (sub-vars chlst env) - (cond [(null? chlst) '()] - [(char=? #\$ (car chlst)) (let [(pair (replace-var (cdr chlst) env))] - (append (string->list (car pair)) - (sub-vars (cdr pair) env)))] - [else (cons (car chlst) (sub-vars (cdr chlst) env))])) - -(define (replace-var chlst env) - (define tok '()) - (define (collect-var-chars chlst) - (if (or (null? chlst) (char=? (car chlst) #\space)) - (set! tok (cons (list->string (reverse tok)) chlst)) - (begin (set! tok (cons (car chlst) tok)) - (collect-var-chars (cdr chlst))))) - (collect-var-chars chlst) - (let [(var (env-get env (car tok)))] - (if var - (cons var (cdr tok)) - (cons "" (cdr tok))))) - -;(define (scan-tok chlst tok) -; (cond [(or (null? chlst) (char=? #\space (car chlst))) -; (list->string (reverse tok))] - -; System Utility Functions -;------------------------------------------------------------------------------ -(define (string-join strlst jstr) - (foldl (lambda (a b) (string-append a b jstr)) "" strlst)) - -; DSL Definition -;------------------------------------------------------------------------------ -(define-syntax task - (syntax-rules (=>) - [(_ name => (deps ...)) - (task-register! (make-task (gen-task-name name) (current-desc) #t '(deps ...) '()))] - [(_ name => (deps ...) exp1 expn ...) - (task-register! - (make-task (gen-task-name name) (current-desc) #t '(deps ...) - (list (lambda () exp1 expn ...))))] - [(_ name exp1 expn ...) - (task-register! - (make-task (gen-task-name name) (current-desc) #t '() - (list (lambda () exp1 expn ...))))])) - -(define-syntax namespace - (syntax-rules () - [(_ name body ...) - (let [(prev-ns (current-namespace))] - (current-namespace (gen-task-name name)) - body ... - (current-namespace prev-ns))])) - -(define (desc str) - (current-desc str)) - -(define-syntax environment - (syntax-rules (<=) - [(_ name <= parent vars ...) - (define name (env-extend parent vars ...))] - [(_ name vars ...) - (define name (env-extend (current-env) vars ...))])) - -(define-syntax builder - (syntax-rules (defaults action) - [(_ (defaults vars ...) (action args body ...)) - (make-builder '(vars ...) (lambda args body ...))])) - -; Core Tasks -;------------------------------------------------------------------------------ -(task "verbose" - (set! verbose #t)) - -(task "help" - (map (lambda (t) - (if (task-desc (cdr t)) - (print (string-append (task-name (cdr t)) " - " (task-desc (cdr t)))))) - top-level-tasks)) -; Main -;------------------------------------------------------------------------------ -(define (run-top-level-tasks!) - (map task-invoke! - (if (= 0 (length (command-line-arguments))) - '("default") - (command-line-arguments)))) - -(load "Spadefile") -(run-top-level-tasks!) - +(declare (uses posix)) +(use posix) + +; Task Definition and Interaction +;------------------------------------------------------------------------------ +(define-record task name desc active? deps actions) + +(define top-level-tasks '()) + +(define current-namespace + (make-parameter '())) + +(define current-desc + (make-parameter #f)) + +(define (task-register! task) + (define name (task-name task)) + (define entry (assoc name top-level-tasks)) + (if (not entry) + (set! top-level-tasks (cons (cons name task) top-level-tasks)) + (set-cdr! entry (task-merge (cdr entry) task)))) + +(define (task-merge task1 task2) + (make-task (task-name task1) (task-desc task1) #t + (append (task-deps task1) + (task-deps task2)) + (append (task-actions task1) + (task-actions task2)))) + +(define (task-lookup name) + (define entry (assoc name top-level-tasks)) + (if (not entry) + (error (string-append "No such task: " name)) + (cdr entry))) + +(define (task-invoke! name) + (define task (task-lookup name)) + (if (task-active? task) + (begin (task-active?-set! task #f) + (map task-invoke! (task-deps task)) + (map (lambda (fn) (fn)) (task-actions task))))) + +(define (gen-task-name name) + (define namespace (current-namespace)) + (if (not (null? namespace)) + (string-append namespace ":" name) + name)) + +; Environment Functions +;------------------------------------------------------------------------------ +(define-record builder defaults action) + +(define (get-sys-env) + (get-environment-variables)) + +(define (set-sys-env! newenv) + (clear-sys-env!) + (map (lambda (p) (setenv (car p) (cdr p))) + newenv)) + +(define (clear-sys-env!) + (map (lambda (p) (unsetenv (car p))) + (get-environment-variables))) + +(define current-env + (let [(curr-env (get-sys-env))] + (lambda args + (if (> (length args) 0) + (begin (set-sys-env! (car args)) + (set! curr-env (car args))) + curr-env)))) + +(define (env-clone env . vars) + (define newenv (map (lambda (p) (cons (car p) (cdr p))) env)) + (define newvals '()) + (map (lambda (e) + (define entry (assoc (car e) newenv)) + (if entry + (set-cdr! entry (cdr e)) + (set! newvals (cons e newvals)))) + vars) + (append newvals newenv)) + +(define (env-get env key) + (define entry (assoc key env)) + (if entry (cdr entry) #f)) + +(define (env-set env key value) + (cons (cons key value) + (env-unset env key))) + +(define (env-unset env key) + (cond [(null? env) '()] + [(string=? (caar env) key) (env-unset (cdr env) key)] + [else (cons (car env) (env-unset (cdr env) key))])) + +(define (env-extend env . vars) + (foldl (lambda (env p) + (env-set env (car p) (cdr p))) + env + vars)) + +(define (env-substitute env str) + (list->string (sub-vars (string->list str) env))) + +(define (env-prepend-path env path) + '()) + +(define (env-append-path env path) + '()) + +(define (env-add-builders env . builders) + '()) + +; Builders +;------------------------------------------------------------------------------ + + +; System Utility Functions +;------------------------------------------------------------------------------ +(define verbose #f) + +(define (build type . args) + (define bldr (assoc type (assoc "builders" (current-env)))) + (define bldr-env (env-merge (builder-defaults bldr) (current-env))) + (apply (builder-action bldr) (cons bldr-env args))) + +(define (run . args) + (define cmd (env-substitute (current-env) (string-join args " "))) + (if verbose (print cmd)) + (if (not (= 0 (system cmd))) + (fail-build cmd))) + +(define (fail-build cmd) + (print "Error: Command returned a non-zero status") + (exit 1)) + +; Directories +(define cd change-directory) +(define curdir current-directory) +(define mkdir create-directory) +(define rmdir delete-directory) +(define lsdir directory) +(define dir? directory?) +; glob + +; Files +(define cp '()) +(define mv '()) +(define rm delete-file) + +; String Templating +;------------------------------------------------------------------------------ +(define (sub-vars chlst env) + (cond [(null? chlst) '()] + [(char=? #\$ (car chlst)) (let [(pair (replace-var (cdr chlst) env))] + (append (string->list (car pair)) + (sub-vars (cdr pair) env)))] + [else (cons (car chlst) (sub-vars (cdr chlst) env))])) + +(define (replace-var chlst env) + (define tok '()) + (define (collect-var-chars chlst) + (if (or (null? chlst) (char=? (car chlst) #\space)) + (set! tok (cons (list->string (reverse tok)) chlst)) + (begin (set! tok (cons (car chlst) tok)) + (collect-var-chars (cdr chlst))))) + (collect-var-chars chlst) + (let [(var (env-get env (car tok)))] + (if var + (cons var (cdr tok)) + (cons "" (cdr tok))))) + +;(define (scan-tok chlst tok) +; (cond [(or (null? chlst) (char=? #\space (car chlst))) +; (list->string (reverse tok))] + +; System Utility Functions +;------------------------------------------------------------------------------ +(define (string-join strlst jstr) + (foldl (lambda (a b) (string-append a b jstr)) "" strlst)) + +; DSL Definition +;------------------------------------------------------------------------------ +(define-syntax task + (syntax-rules (=>) + [(_ name => (deps ...)) + (task-register! (make-task (gen-task-name name) (current-desc) #t '(deps ...) '()))] + [(_ name => (deps ...) exp1 expn ...) + (task-register! + (make-task (gen-task-name name) (current-desc) #t '(deps ...) + (list (lambda () exp1 expn ...))))] + [(_ name exp1 expn ...) + (task-register! + (make-task (gen-task-name name) (current-desc) #t '() + (list (lambda () exp1 expn ...))))])) + +(define-syntax namespace + (syntax-rules () + [(_ name body ...) + (let [(prev-ns (current-namespace))] + (current-namespace (gen-task-name name)) + body ... + (current-namespace prev-ns))])) + +(define (desc str) + (current-desc str)) + +(define-syntax environment + (syntax-rules (<=) + [(_ name <= parent vars ...) + (define name (env-extend parent vars ...))] + [(_ name vars ...) + (define name (env-extend (current-env) vars ...))])) + +(define-syntax builder + (syntax-rules (defaults action) + [(_ (defaults vars ...) (action args body ...)) + (make-builder '(vars ...) (lambda args body ...))])) + +; Core Tasks +;------------------------------------------------------------------------------ +(task "verbose" + (set! verbose #t)) + +(task "help" + (map (lambda (t) + (if (task-desc (cdr t)) + (print (string-append (task-name (cdr t)) " - " (task-desc (cdr t)))))) + top-level-tasks)) +; Main +;------------------------------------------------------------------------------ +(define (run-top-level-tasks!) + (map task-invoke! + (if (= 0 (length (command-line-arguments))) + '("default") + (command-line-arguments)))) + +(load "Spadefile") +(run-top-level-tasks!) + diff --git a/source/slc/main.scm b/source/slc/main.scm index 5ce0777..5079ac5 100644 --- a/source/slc/main.scm +++ b/source/slc/main.scm @@ -1,412 +1,412 @@ -; Regex Matching Macro -;------------------------------------------------------------------------------ -(use regex ports extras) - -(define-syntax regex-case - (syntax-rules (else) - ((_ item (else result1 result2 ...)) - (begin result1 result2 ...)) - - ((_ item (regex result1 result2 ...)) - (if (string-match regex item) (begin result1 result2 ...))) - - ((_ item (regex result1 result2 ...) clause1 clause2 ...) - (if (string-match regex item) - (begin result1 result2 ...) - (regex-case item clause1 clause2 ...))))) - -; Reader Phase -;------------------------------------------------------------------------------ -; This phase is responsible reading input from a port and constructing the -; expression that the input represents. - -(define (sclpl-read port) - (let [(tok (read-token port))] - (if (eof-object? tok) - tok - (cond [(list-op? tok) (read-sexp port (get-sexp-term tok))] - [(equal? "'" tok) `(quote ,(sclpl-read port))] - [(equal? "`" tok) `(quasiquote ,(sclpl-read port))] - [else (classify-atom tok)])))) - -(define (read-sexp port term) - (define expr (sclpl-read port)) - (cond [(equal? expr term) '()] - [(wrong-term? expr term) (error "Incorrectly matched list terminator")] - [(equal? '|.| expr) (read-and-term port term)] - [else (cons expr (read-sexp port term))])) - - -(define (read-and-term port term) - (define val (sclpl-read port)) - (define tval (sclpl-read port)) - (cond [(member val '(#\) #\] #\})) (error "")] - [(equal? tval term) val] - [(wrong-term? tval term) (error "")] - [else (error "")])) - -(define (classify-atom atom) - (regex-case atom - ["nil" '()] - ["true" #t] - ["false" #f] - ["^\".*\"$" (dequote atom)] - ["^\\\\.+" (atom->char atom)] - ["[{[()\\]}]" (string-ref atom 0)] - ["#[dbox](#[ie])?.+" (or (string->number atom) (string->symbol atom))] - ["[+-]?[0-9].*" (or (string->number atom) (string->symbol atom))] - [else (if (string-literal? atom) - (dequote atom) - (string->symbol atom))])) - -(define (list-op? tok) - (member (string-ref tok 0) '(#\( #\[ #\{))) - -(define (get-sexp-term tok) - (define pairs '((#\( . #\)) (#\[ . #\]) (#\{ . #\}))) - (define term (assv (string-ref tok 0) pairs)) - (if term (cdr term) (error "Not a valid s-expression delimiter"))) - -(define (wrong-term? expr term) - (define terms '(#\) #\] #\})) - (and (not (equal? expr term)) - (member expr terms))) - -(define (string-literal? atom) - (and (char=? #\" (string-ref atom 0)) - (char=? #\" (string-ref atom (- (string-length atom) 1))))) - -(define (dequote str) - (substring str 1 (- (string-length str) 1))) - -(define (atom->char atom) - (define ch-name (substring atom 1)) - (define ch (if (= 1 (string-length ch-name)) - (string-ref ch-name 0) - (char-name (string->symbol ch-name)))) - (or ch (error (string-append "Invalid character name: " ch-name)))) - -;------------------------------------------------------------------------------ - -(define whitespace (string->list " \t\r\n")) -(define punctuation (string->list "()[]{}'`:,")) -(define delimiters (string->list "()[]{}'`:,; \t\r\n")) -(define doublequote '(#\")) - -(define (read-token port) - (define ch (peek-char port)) - (define tok - (cond [(eof-object? ch) ch] - [(member ch whitespace) (consume-whitespace port)] - [(char=? ch #\;) (consume-comment port)] - [(char=? ch #\") (read-till-next #t port doublequote)] - [(member ch punctuation) (string (read-char port))] - [else (read-till-next #f port delimiters)])) - (if (list? tok) (list->string tok) tok)) - -(define (consume-whitespace port) - (if (member (peek-char port) whitespace) - (read-char port)) - (read-token port)) - -(define (consume-comment port) - (if (not (char=? #\newline (peek-char port))) - (begin (read-char port) - (consume-comment port)) - (begin (read-char port) - (read-token port)))) - -(define (read-till-next inc port delims) - (cons (read-char port) - (if (or (member (peek-char port) delims) - (eof-object? (peek-char port))) - (if inc (cons (read-char port) '()) '()) - (read-till-next inc port delims)))) - -; Macro Expansion Phase -;------------------------------------------------------------------------------ -; This phase is responsible for taking the expressions read from the input port -; and performing macro expansion on them to get the resulting expression. - -(define (expand-macros expr) - expr) - -; Desugaring Phase -;------------------------------------------------------------------------------ -; The desugaring phase is responsible for taking user friendly extensions to -; the core SCLPL syntax and deconstructing them into the low-level counterparts -; defined by the "core" SCLPL syntax. This allows the code generator to work on -; a small and well-defined subset of the SCLPL language. - -(define (desugar expr) - (cond [(not (pair? expr)) expr] - [(eqv? 'def (car expr)) (desugar-def expr)] - [(eqv? 'if (car expr)) (desugar-if expr)] - [(eqv? 'fn (car expr)) (append (list 'fn (cadr expr)) - (map desugar (cddr expr)))] - [else (map desugar expr)])) - -(define (desugar-def expr) - (cond [(annotated-def? expr) (desugar-annotated-def expr)] - [(sugared-def? expr) (desugar-sugared-def expr)] - [else (map desugar expr)])) - -(define (annotated-def? expr) - (and (form-structure-valid? 'def >= 4 expr) - (eqv? ': (caddr expr)))) - -(define (sugared-def? expr) - (and (form-structure-valid? 'def >= 2 expr) - (arg-list-valid? (cadr expr)))) - -(define (desugar-annotated-def expr) - (let [(proto (cadr expr)) - (type (cadddr expr)) - (body (cddddr expr))] - (if (pair? proto) - (append `(def (,(car proto) ,type)) - (list (append `(fn ,(cdr proto)) (map desugar body)))) - (append `(def (,proto ,type)) - (map desugar body))))) - -(define (desugar-sugared-def expr) - (if (pair? (cadr expr)) - (append `(def (,(caadr expr) ())) - (list (append `(fn ,(cdadr expr)) (map desugar (cddr expr))))) - (append `(def (,(cadr expr) ())) (map desugar (cddr expr))))) - -(define (desugar-if expr) - (if (form-structure-valid? 'if = 3 expr) - (map desugar (append expr '('()))) - (map desugar expr))) - -; Analysis Phase -;------------------------------------------------------------------------------ -; The analysis phase is responsible for verifying that the provided expression -; conforms to the requirements of the "core" SCLPL syntax. This phase will throw -; an error for any invalid expression or simply return the provided expression -; if it is valid. - -(define (analyze expr) - (if (list? expr) - (analyze-form expr) - expr)) - -(define (analyze-form expr) - (if (null? expr) - (error-msg 'non-atomic expr) - (case (car expr) - [(def) (analyze-def expr)] - [(fn) (analyze-fn expr)] - [(if) (validate-and-analyze 'if = 4 expr)] - [(do) (validate-and-analyze 'do >= 1 expr)] - [(quote) (validate-and-analyze 'quote = 2 expr)] - [else (map analyze expr)]))) - -(define (analyze-def expr) - (validate-form 'def = 3 expr) - (validate-signature (cadr expr)) - expr) - -(define (analyze-fn expr) - (if (and (form-structure-valid? 'fn >= 3 expr) - (arg-list-valid? (cadr expr))) - (append (list 'fn (cadr expr)) - (map analyze (cddr expr))) - (error-msg 'invalid-fn expr))) - -(define (validate-and-analyze type cmpop nargs expr) - (validate-form type cmpop nargs expr) - (map analyze expr)) - -(define (validate-form type cmpop nargs expr) - (cond [(not (pair? expr)) (error-msg 'not-an-sexp expr)] - [(not (eqv? type (car expr))) (error-msg 'wrong-form-type expr)] - [(not (cmpop (length expr) nargs)) (error-msg 'num-args expr)])) - -(define (validate-signature sig) - (cond [(not (list? sig)) (error-msg 'sig-not-list sig)] - [(not (= 2 (length sig))) (error-msg 'sig-num-entries sig)] - [(not (variable? (car sig))) (error-msg 'sig-variable sig)] - ;[(not (type? (cadr sig))) (error-msg 'expect-type sig)])) - )) - -; Type Checking Phase -;------------------------------------------------------------------------------ -; This phase is responsible for performing type reconstruction and verifying -; that the expression is well-typed before being passed to the optimization and -; compilation phases - -(define (check-type expr env) - expr) - -; CPS-Conversion Phase -;------------------------------------------------------------------------------ -; This phase translates the fully macro-expanded, desugared, and analyzed -; program into continuation-passing style so various optimizations can be -; performed before code is generated. - -(define (cps-convert expr) - expr) - -; SCLPL to Scheme Phase -;------------------------------------------------------------------------------ - -(define (sclpl->scheme expr) - expr) - -; Error Messages -;------------------------------------------------------------------------------ -(define (error-msg type expr . args) - (let [(handler (assoc type error-handlers))] - (if handler (apply (cdr handler) args) (apply unknown-error args)) - (log-msg (with-output-to-string (lambda () (pretty-print expr)))) - (fail expr))) - -(define (non-atomic-expr) - (log-msg "Error: Illegal non-atomic object")) - -(define (invalid-fn) - (log-msg "Error: Invalid function form")) - -(define (not-an-sexpr) - (log-msg "Error: Not an s-expression")) - -(define (wrong-form-type) - (log-msg "Error: Incorrect form type")) - -(define (wrong-num-args) - (log-msg "Error: Incorrect number of args for form")) - -(define (sig-is-not-a-list) - (log-msg "Error: Function signature is not a list")) - -(define (wrong-num-sig-parts) - (log-msg "Error: Function signature has incorrect number of parts")) - -(define (sig-name-not-var) - (log-msg "Error: Name part of function signature is not a variable")) - -(define (expected-:) - (log-msg "Error: Expected a :")) - -(define (unknown-error . args) - (log-msg "Error: Unknown error occurred in the following expression")) - -(define error-handlers - `((non-atomic . ,non-atomic-expr) - (invalid-fn . ,invalid-fn) - (not-an-sexp . ,not-an-sexpr) - (wrong-form-type . ,wrong-form-type) - (num-args . ,wrong-num-args) - (sig-not-list . ,sig-is-not-a-list) - (sig-num-entries . ,wrong-num-sig-parts) - (sig-variable . ,sig-name-not-var) - (expect-: . ,expected-:))) - -; Helper Predicates -;------------------------------------------------------------------------------ -; This collection of predicate functions is used to assist the earlier phases -; when dealing with similar data-structures. - -(define (form-structure-valid? type cmpop nargs expr) - (and (pair? expr) - (eqv? type (car expr)) - (cmpop (length expr) nargs))) - -(define (arg-list-valid? arglst) - (or (variable? arglst) - (and (or (list? arglst) (pair? arglst)) - (list-of? variable? arglst)))) - -(define (list-of? type lst) - (if (null? lst) #t - (if (type (car lst)) - (if (type (cdr lst)) #t (list-of? type (cdr lst))) - #f))) - -(define (variable? sym) - (and (symbol? sym) - (not (type-name? sym)) - (not (type-var? sym)))) - -(define (atomic-base-type? type) - (if (member type '(Any Number Symbol String Char Bool)) #t #f)) - -(define (type? expr) - (cond [(null? expr) #f] - [(member '-> expr) (fn-type? expr)] - [(list? expr) (and (> (length expr) 1) - (apply list-and? (map type? expr)))] - [else (or (type-name? expr) (type-var? expr))])) - -(define (type-name? sym) - (and (symbol? sym) - (let [(ch (string-ref (symbol->string sym) 0))] - (and (char>=? ch #\A) (char<=? ch #\Z))))) - -(define (type-var? sym) - (and (symbol? sym) - (let [(ch (string-ref (symbol->string sym) 0))] - (char=? ch #\?)))) - -(define (fn-type? expr) - (define (is-fn-type? prev expr) - (if (null? expr) #t - (case (car expr) - [(...) (and (type? prev) - (>= (length (cdr expr)) 1) - (equal? '-> (cadr expr)) - (is-fn-type? #f (cdr expr)))] - [(->) (and (= 2 (length expr)) - (is-fn-type? (car expr) (cdr expr)))] - [else (and (type? (car expr)) - (is-fn-type? (car expr) (cdr expr)))]))) - (is-fn-type? #f expr)) - -(define (list-and? . args) - (if (null? args) #t (and (car args) (apply list-and? (cdr args))))) - -; Main -;------------------------------------------------------------------------------ - -(define fail error) - -(define log-msg (lambda args '())) - -;(define (print-data . args) -; (apply print -; (map (lambda (e) -; (if (string? e) -; e -; (with-output-to-string (lambda () (pretty-print e))))) -; args))) - -;(define (interpret port) -; (call/cc (lambda (k) -; (set! fail k) -; (set! log-msg print) -; (display (string-append ":" (sexp-count) "> ")) -; ; Read and type and analyze all expressions from input -; (define expr (sclpl-read port)) -; (print-data "Read Phase: \n" expr) -; (set! expr (expand-macros expr)) -; (print-data "Macro Expansion Phase: \n" expr) -; (set! expr (desugar expr)) -; (print-data "Desugar Phase: \n" expr) -; (set! expr (analyze expr)) -; (print-data "Analysis Phase: \n" expr))) -; (interpret port)) -;(interpret (current-input-port)) -;(exit) - -(define (read-program port) - (define expr (sclpl-read port)) - (if (eof-object? expr) - '() - (cons (analyze (desugar (expand-macros expr))) - (read-program port)))) - -(print (read-program (current-input-port))) - - +; Regex Matching Macro +;------------------------------------------------------------------------------ +(use regex ports extras) + +(define-syntax regex-case + (syntax-rules (else) + ((_ item (else result1 result2 ...)) + (begin result1 result2 ...)) + + ((_ item (regex result1 result2 ...)) + (if (string-match regex item) (begin result1 result2 ...))) + + ((_ item (regex result1 result2 ...) clause1 clause2 ...) + (if (string-match regex item) + (begin result1 result2 ...) + (regex-case item clause1 clause2 ...))))) + +; Reader Phase +;------------------------------------------------------------------------------ +; This phase is responsible reading input from a port and constructing the +; expression that the input represents. + +(define (sclpl-read port) + (let [(tok (read-token port))] + (if (eof-object? tok) + tok + (cond [(list-op? tok) (read-sexp port (get-sexp-term tok))] + [(equal? "'" tok) `(quote ,(sclpl-read port))] + [(equal? "`" tok) `(quasiquote ,(sclpl-read port))] + [else (classify-atom tok)])))) + +(define (read-sexp port term) + (define expr (sclpl-read port)) + (cond [(equal? expr term) '()] + [(wrong-term? expr term) (error "Incorrectly matched list terminator")] + [(equal? '|.| expr) (read-and-term port term)] + [else (cons expr (read-sexp port term))])) + + +(define (read-and-term port term) + (define val (sclpl-read port)) + (define tval (sclpl-read port)) + (cond [(member val '(#\) #\] #\})) (error "")] + [(equal? tval term) val] + [(wrong-term? tval term) (error "")] + [else (error "")])) + +(define (classify-atom atom) + (regex-case atom + ["nil" '()] + ["true" #t] + ["false" #f] + ["^\".*\"$" (dequote atom)] + ["^\\\\.+" (atom->char atom)] + ["[{[()\\]}]" (string-ref atom 0)] + ["#[dbox](#[ie])?.+" (or (string->number atom) (string->symbol atom))] + ["[+-]?[0-9].*" (or (string->number atom) (string->symbol atom))] + [else (if (string-literal? atom) + (dequote atom) + (string->symbol atom))])) + +(define (list-op? tok) + (member (string-ref tok 0) '(#\( #\[ #\{))) + +(define (get-sexp-term tok) + (define pairs '((#\( . #\)) (#\[ . #\]) (#\{ . #\}))) + (define term (assv (string-ref tok 0) pairs)) + (if term (cdr term) (error "Not a valid s-expression delimiter"))) + +(define (wrong-term? expr term) + (define terms '(#\) #\] #\})) + (and (not (equal? expr term)) + (member expr terms))) + +(define (string-literal? atom) + (and (char=? #\" (string-ref atom 0)) + (char=? #\" (string-ref atom (- (string-length atom) 1))))) + +(define (dequote str) + (substring str 1 (- (string-length str) 1))) + +(define (atom->char atom) + (define ch-name (substring atom 1)) + (define ch (if (= 1 (string-length ch-name)) + (string-ref ch-name 0) + (char-name (string->symbol ch-name)))) + (or ch (error (string-append "Invalid character name: " ch-name)))) + +;------------------------------------------------------------------------------ + +(define whitespace (string->list " \t\r\n")) +(define punctuation (string->list "()[]{}'`:,")) +(define delimiters (string->list "()[]{}'`:,; \t\r\n")) +(define doublequote '(#\")) + +(define (read-token port) + (define ch (peek-char port)) + (define tok + (cond [(eof-object? ch) ch] + [(member ch whitespace) (consume-whitespace port)] + [(char=? ch #\;) (consume-comment port)] + [(char=? ch #\") (read-till-next #t port doublequote)] + [(member ch punctuation) (string (read-char port))] + [else (read-till-next #f port delimiters)])) + (if (list? tok) (list->string tok) tok)) + +(define (consume-whitespace port) + (if (member (peek-char port) whitespace) + (read-char port)) + (read-token port)) + +(define (consume-comment port) + (if (not (char=? #\newline (peek-char port))) + (begin (read-char port) + (consume-comment port)) + (begin (read-char port) + (read-token port)))) + +(define (read-till-next inc port delims) + (cons (read-char port) + (if (or (member (peek-char port) delims) + (eof-object? (peek-char port))) + (if inc (cons (read-char port) '()) '()) + (read-till-next inc port delims)))) + +; Macro Expansion Phase +;------------------------------------------------------------------------------ +; This phase is responsible for taking the expressions read from the input port +; and performing macro expansion on them to get the resulting expression. + +(define (expand-macros expr) + expr) + +; Desugaring Phase +;------------------------------------------------------------------------------ +; The desugaring phase is responsible for taking user friendly extensions to +; the core SCLPL syntax and deconstructing them into the low-level counterparts +; defined by the "core" SCLPL syntax. This allows the code generator to work on +; a small and well-defined subset of the SCLPL language. + +(define (desugar expr) + (cond [(not (pair? expr)) expr] + [(eqv? 'def (car expr)) (desugar-def expr)] + [(eqv? 'if (car expr)) (desugar-if expr)] + [(eqv? 'fn (car expr)) (append (list 'fn (cadr expr)) + (map desugar (cddr expr)))] + [else (map desugar expr)])) + +(define (desugar-def expr) + (cond [(annotated-def? expr) (desugar-annotated-def expr)] + [(sugared-def? expr) (desugar-sugared-def expr)] + [else (map desugar expr)])) + +(define (annotated-def? expr) + (and (form-structure-valid? 'def >= 4 expr) + (eqv? ': (caddr expr)))) + +(define (sugared-def? expr) + (and (form-structure-valid? 'def >= 2 expr) + (arg-list-valid? (cadr expr)))) + +(define (desugar-annotated-def expr) + (let [(proto (cadr expr)) + (type (cadddr expr)) + (body (cddddr expr))] + (if (pair? proto) + (append `(def (,(car proto) ,type)) + (list (append `(fn ,(cdr proto)) (map desugar body)))) + (append `(def (,proto ,type)) + (map desugar body))))) + +(define (desugar-sugared-def expr) + (if (pair? (cadr expr)) + (append `(def (,(caadr expr) ())) + (list (append `(fn ,(cdadr expr)) (map desugar (cddr expr))))) + (append `(def (,(cadr expr) ())) (map desugar (cddr expr))))) + +(define (desugar-if expr) + (if (form-structure-valid? 'if = 3 expr) + (map desugar (append expr '('()))) + (map desugar expr))) + +; Analysis Phase +;------------------------------------------------------------------------------ +; The analysis phase is responsible for verifying that the provided expression +; conforms to the requirements of the "core" SCLPL syntax. This phase will throw +; an error for any invalid expression or simply return the provided expression +; if it is valid. + +(define (analyze expr) + (if (list? expr) + (analyze-form expr) + expr)) + +(define (analyze-form expr) + (if (null? expr) + (error-msg 'non-atomic expr) + (case (car expr) + [(def) (analyze-def expr)] + [(fn) (analyze-fn expr)] + [(if) (validate-and-analyze 'if = 4 expr)] + [(do) (validate-and-analyze 'do >= 1 expr)] + [(quote) (validate-and-analyze 'quote = 2 expr)] + [else (map analyze expr)]))) + +(define (analyze-def expr) + (validate-form 'def = 3 expr) + (validate-signature (cadr expr)) + expr) + +(define (analyze-fn expr) + (if (and (form-structure-valid? 'fn >= 3 expr) + (arg-list-valid? (cadr expr))) + (append (list 'fn (cadr expr)) + (map analyze (cddr expr))) + (error-msg 'invalid-fn expr))) + +(define (validate-and-analyze type cmpop nargs expr) + (validate-form type cmpop nargs expr) + (map analyze expr)) + +(define (validate-form type cmpop nargs expr) + (cond [(not (pair? expr)) (error-msg 'not-an-sexp expr)] + [(not (eqv? type (car expr))) (error-msg 'wrong-form-type expr)] + [(not (cmpop (length expr) nargs)) (error-msg 'num-args expr)])) + +(define (validate-signature sig) + (cond [(not (list? sig)) (error-msg 'sig-not-list sig)] + [(not (= 2 (length sig))) (error-msg 'sig-num-entries sig)] + [(not (variable? (car sig))) (error-msg 'sig-variable sig)] + ;[(not (type? (cadr sig))) (error-msg 'expect-type sig)])) + )) + +; Type Checking Phase +;------------------------------------------------------------------------------ +; This phase is responsible for performing type reconstruction and verifying +; that the expression is well-typed before being passed to the optimization and +; compilation phases + +(define (check-type expr env) + expr) + +; CPS-Conversion Phase +;------------------------------------------------------------------------------ +; This phase translates the fully macro-expanded, desugared, and analyzed +; program into continuation-passing style so various optimizations can be +; performed before code is generated. + +(define (cps-convert expr) + expr) + +; SCLPL to Scheme Phase +;------------------------------------------------------------------------------ + +(define (sclpl->scheme expr) + expr) + +; Error Messages +;------------------------------------------------------------------------------ +(define (error-msg type expr . args) + (let [(handler (assoc type error-handlers))] + (if handler (apply (cdr handler) args) (apply unknown-error args)) + (log-msg (with-output-to-string (lambda () (pretty-print expr)))) + (fail expr))) + +(define (non-atomic-expr) + (log-msg "Error: Illegal non-atomic object")) + +(define (invalid-fn) + (log-msg "Error: Invalid function form")) + +(define (not-an-sexpr) + (log-msg "Error: Not an s-expression")) + +(define (wrong-form-type) + (log-msg "Error: Incorrect form type")) + +(define (wrong-num-args) + (log-msg "Error: Incorrect number of args for form")) + +(define (sig-is-not-a-list) + (log-msg "Error: Function signature is not a list")) + +(define (wrong-num-sig-parts) + (log-msg "Error: Function signature has incorrect number of parts")) + +(define (sig-name-not-var) + (log-msg "Error: Name part of function signature is not a variable")) + +(define (expected-:) + (log-msg "Error: Expected a :")) + +(define (unknown-error . args) + (log-msg "Error: Unknown error occurred in the following expression")) + +(define error-handlers + `((non-atomic . ,non-atomic-expr) + (invalid-fn . ,invalid-fn) + (not-an-sexp . ,not-an-sexpr) + (wrong-form-type . ,wrong-form-type) + (num-args . ,wrong-num-args) + (sig-not-list . ,sig-is-not-a-list) + (sig-num-entries . ,wrong-num-sig-parts) + (sig-variable . ,sig-name-not-var) + (expect-: . ,expected-:))) + +; Helper Predicates +;------------------------------------------------------------------------------ +; This collection of predicate functions is used to assist the earlier phases +; when dealing with similar data-structures. + +(define (form-structure-valid? type cmpop nargs expr) + (and (pair? expr) + (eqv? type (car expr)) + (cmpop (length expr) nargs))) + +(define (arg-list-valid? arglst) + (or (variable? arglst) + (and (or (list? arglst) (pair? arglst)) + (list-of? variable? arglst)))) + +(define (list-of? type lst) + (if (null? lst) #t + (if (type (car lst)) + (if (type (cdr lst)) #t (list-of? type (cdr lst))) + #f))) + +(define (variable? sym) + (and (symbol? sym) + (not (type-name? sym)) + (not (type-var? sym)))) + +(define (atomic-base-type? type) + (if (member type '(Any Number Symbol String Char Bool)) #t #f)) + +(define (type? expr) + (cond [(null? expr) #f] + [(member '-> expr) (fn-type? expr)] + [(list? expr) (and (> (length expr) 1) + (apply list-and? (map type? expr)))] + [else (or (type-name? expr) (type-var? expr))])) + +(define (type-name? sym) + (and (symbol? sym) + (let [(ch (string-ref (symbol->string sym) 0))] + (and (char>=? ch #\A) (char<=? ch #\Z))))) + +(define (type-var? sym) + (and (symbol? sym) + (let [(ch (string-ref (symbol->string sym) 0))] + (char=? ch #\?)))) + +(define (fn-type? expr) + (define (is-fn-type? prev expr) + (if (null? expr) #t + (case (car expr) + [(...) (and (type? prev) + (>= (length (cdr expr)) 1) + (equal? '-> (cadr expr)) + (is-fn-type? #f (cdr expr)))] + [(->) (and (= 2 (length expr)) + (is-fn-type? (car expr) (cdr expr)))] + [else (and (type? (car expr)) + (is-fn-type? (car expr) (cdr expr)))]))) + (is-fn-type? #f expr)) + +(define (list-and? . args) + (if (null? args) #t (and (car args) (apply list-and? (cdr args))))) + +; Main +;------------------------------------------------------------------------------ + +(define fail error) + +(define log-msg (lambda args '())) + +;(define (print-data . args) +; (apply print +; (map (lambda (e) +; (if (string? e) +; e +; (with-output-to-string (lambda () (pretty-print e))))) +; args))) + +;(define (interpret port) +; (call/cc (lambda (k) +; (set! fail k) +; (set! log-msg print) +; (display (string-append ":" (sexp-count) "> ")) +; ; Read and type and analyze all expressions from input +; (define expr (sclpl-read port)) +; (print-data "Read Phase: \n" expr) +; (set! expr (expand-macros expr)) +; (print-data "Macro Expansion Phase: \n" expr) +; (set! expr (desugar expr)) +; (print-data "Desugar Phase: \n" expr) +; (set! expr (analyze expr)) +; (print-data "Analysis Phase: \n" expr))) +; (interpret port)) +;(interpret (current-input-port)) +;(exit) + +(define (read-program port) + (define expr (sclpl-read port)) + (if (eof-object? expr) + '() + (cons (analyze (desugar (expand-macros expr))) + (read-program port)))) + +(print (read-program (current-input-port))) + + diff --git a/source/slpkg/main.scm b/source/slpkg/main.scm index eccc64e..2d821a1 100644 --- a/source/slpkg/main.scm +++ b/source/slpkg/main.scm @@ -1,72 +1,72 @@ -(declare (uses library server)) - -(define slpkg-usage -"Package manager for SCLPL (Simple Concurrent List Processing Language). - -Usage: - slpkg [COMMAND] [OPTIONS] - -Commands: - help Show help documentation for a specific command or subcommand. - install Install one or more packages from the configured sources. - publish Publish a package to a specified repository. - remove Remove one or more packages from this machine. - search Search the repositories for packages matching a pattern. - server Start a package server to host packages. - show Show detailed information about a specific package or packages. - source Manage the sources from which packages will be retrieved. - update Update the package lists for all configured sources. - upgrade Upgrade a given package or packages. -") - -;------------------------------------------------------------------------------ - -(define (help-cmd args) - (print args)) - -;------------------------------------------------------------------------------ -(define install-cmd help-cmd) -;------------------------------------------------------------------------------ -(define publish-cmd help-cmd) -;------------------------------------------------------------------------------ -(define remove-cmd help-cmd) -;------------------------------------------------------------------------------ -(define search-cmd help-cmd) -;------------------------------------------------------------------------------ - -(define (server-cmd args) - (start-pkg-server (cadr args) (caddr args))) - -;------------------------------------------------------------------------------ -(define show-cmd help-cmd) -;------------------------------------------------------------------------------ -(define source-cmd help-cmd) -;------------------------------------------------------------------------------ -(define update-cmd help-cmd) -;------------------------------------------------------------------------------ -(define upgrade-cmd help-cmd) -;------------------------------------------------------------------------------ - -(define slpkg-commands - `(("help" . ,help-cmd) - ("install" . ,install-cmd) - ("publish" . ,publish-cmd) - ("remove" . ,remove-cmd) - ("search" . ,search-cmd) - ("server" . ,server-cmd) - ("show" . ,show-cmd) - ("source" . ,source-cmd) - ("update" . ,update-cmd) - ("upgrade" . ,upgrade-cmd))) - -;------------------------------------------------------------------------------ - -(define (cmd-dispatch cmd-map usage args) - (define sub-cmd (if (pair? args) (assoc (car args) cmd-map) '())) - (cond [(pair? sub-cmd) ((cdr sub-cmd) (cdr args))] - [else (print usage)])) - -;------------------------------------------------------------------------------ - -(cmd-dispatch slpkg-commands slpkg-usage (command-line-arguments)) - +(declare (uses library server)) + +(define slpkg-usage +"Package manager for SCLPL (Simple Concurrent List Processing Language). + +Usage: + slpkg [COMMAND] [OPTIONS] + +Commands: + help Show help documentation for a specific command or subcommand. + install Install one or more packages from the configured sources. + publish Publish a package to a specified repository. + remove Remove one or more packages from this machine. + search Search the repositories for packages matching a pattern. + server Start a package server to host packages. + show Show detailed information about a specific package or packages. + source Manage the sources from which packages will be retrieved. + update Update the package lists for all configured sources. + upgrade Upgrade a given package or packages. +") + +;------------------------------------------------------------------------------ + +(define (help-cmd args) + (print args)) + +;------------------------------------------------------------------------------ +(define install-cmd help-cmd) +;------------------------------------------------------------------------------ +(define publish-cmd help-cmd) +;------------------------------------------------------------------------------ +(define remove-cmd help-cmd) +;------------------------------------------------------------------------------ +(define search-cmd help-cmd) +;------------------------------------------------------------------------------ + +(define (server-cmd args) + (start-pkg-server (cadr args) (caddr args))) + +;------------------------------------------------------------------------------ +(define show-cmd help-cmd) +;------------------------------------------------------------------------------ +(define source-cmd help-cmd) +;------------------------------------------------------------------------------ +(define update-cmd help-cmd) +;------------------------------------------------------------------------------ +(define upgrade-cmd help-cmd) +;------------------------------------------------------------------------------ + +(define slpkg-commands + `(("help" . ,help-cmd) + ("install" . ,install-cmd) + ("publish" . ,publish-cmd) + ("remove" . ,remove-cmd) + ("search" . ,search-cmd) + ("server" . ,server-cmd) + ("show" . ,show-cmd) + ("source" . ,source-cmd) + ("update" . ,update-cmd) + ("upgrade" . ,upgrade-cmd))) + +;------------------------------------------------------------------------------ + +(define (cmd-dispatch cmd-map usage args) + (define sub-cmd (if (pair? args) (assoc (car args) cmd-map) '())) + (cond [(pair? sub-cmd) ((cdr sub-cmd) (cdr args))] + [else (print usage)])) + +;------------------------------------------------------------------------------ + +(cmd-dispatch slpkg-commands slpkg-usage (command-line-arguments)) + diff --git a/source/slpkg/server.scm b/source/slpkg/server.scm index 983f9da..9b33a38 100644 --- a/source/slpkg/server.scm +++ b/source/slpkg/server.scm @@ -1,44 +1,44 @@ -(declare (unit server) (uses eval));(uses spiffy intarweb posix)) -(require-extension spiffy) - -(define index-template -" - - - Index of ~a - - -
~a
- -") - -(define entry-template "~a
\n") - -(define (html-response html) - (with-headers `((content-type text/html) - (content-length ,(string-length html))) - (lambda () - (write-logged-response) - (display html (response-port (current-response)))))) - -(define (generate-index path) - (define curr_root (string-append (root-path) path)) - (define entries (glob (string-append curr_root "/*"))) - (apply string-append - (map (lambda (e) - (define pth (if (equal? "/" path) path (string-append path "/" e))) - (sprintf entry-template pth e)) - (map (lambda (e) (car (reverse (string-split e "/")))) - entries)))) - -(define (index-handler path) - (html-response (sprintf index-template path (generate-index path)))) - -(define (start-pkg-server port root) - (server-port port) - (root-path root) - (handle-directory index-handler) - (start-server)) - +(declare (unit server) (uses eval));(uses spiffy intarweb posix)) +(require-extension spiffy) + +(define index-template +" + + + Index of ~a + + +
~a
+ +") + +(define entry-template "~a
\n") + +(define (html-response html) + (with-headers `((content-type text/html) + (content-length ,(string-length html))) + (lambda () + (write-logged-response) + (display html (response-port (current-response)))))) + +(define (generate-index path) + (define curr_root (string-append (root-path) path)) + (define entries (glob (string-append curr_root "/*"))) + (apply string-append + (map (lambda (e) + (define pth (if (equal? "/" path) path (string-append path "/" e))) + (sprintf entry-template pth e)) + (map (lambda (e) (car (reverse (string-split e "/")))) + entries)))) + +(define (index-handler path) + (html-response (sprintf index-template path (generate-index path)))) + +(define (start-pkg-server port root) + (server-port port) + (root-path root) + (handle-directory index-handler) + (start-server)) + diff --git a/source/slvm/kernel/parser.h b/source/slvm/kernel/parser.h index 42a32bd..2fca4aa 100644 --- a/source/slvm/kernel/parser.h +++ b/source/slvm/kernel/parser.h @@ -1,27 +1,27 @@ -/** - @file parser.h - @brief TODO: Describe this file - $Revision$ - $HeadURL$ - */ -#ifndef PARSER_H -#define PARSER_H - -#include "slvm.h" -#include -#include - -typedef enum { - ERROR = 0, - WORD, - STRING, - CHAR, - INTEGER, - FLOAT, -} TokenType_T; - -char* fetch_token(void); - -TokenType_T parse_token(char* str, val_t* p_val); - -#endif /* PARSER_H */ +/** + @file parser.h + @brief TODO: Describe this file + $Revision$ + $HeadURL$ + */ +#ifndef PARSER_H +#define PARSER_H + +#include "slvm.h" +#include +#include + +typedef enum { + ERROR = 0, + WORD, + STRING, + CHAR, + INTEGER, + FLOAT, +} TokenType_T; + +char* fetch_token(void); + +TokenType_T parse_token(char* str, val_t* p_val); + +#endif /* PARSER_H */ diff --git a/source/slvm/kernel/slvm.c b/source/slvm/kernel/slvm.c index 5640ef6..35e7663 100644 --- a/source/slvm/kernel/slvm.c +++ b/source/slvm/kernel/slvm.c @@ -1,549 +1,549 @@ -#include "slvm.h" -#include "parser.h" -#include "pal.h" - -/* - Wish List: - - * Dynamic Loading and Unloading of Dictionaries (File, Object, or Dynamic Lib) - * Rework w* words to allow gettign and setting attributes of a word - * Add optional debugging words - * Add optional floating point / fixed point words - * Add optional runtime integrity checks - * Add optional static heap replacement for malloc, realloc, free - * Add optional support for embedded systems (No dependence on stdlib) - * Run through profiler and optimize execution speed where possible. - * Add optional support for temporaries - * Add optional code optimizer for compiled words - * Add ability to compile to simple object file - * Add ability to compile to shared library - * Add ability to compile to standalone executable - * Add support for multi-tasking - * Add support for multi-tasking with multiple cores/threads - -*/ - -/* Inner Interpreter - *****************************************************************************/ -void docolon(val_t* code) { - word_t* word; - /* We may have previously been executing a word so we should save off our - * previous position */ - val_t* prev_code = CodePtr; - /* Set the next instruction to execute */ - CodePtr = code; - /* Loop through until "ret" sets the code pointer to null */ - while(CodePtr) - { - word = (word_t*)*CodePtr; - /* Increment the instruction pointer */ - CodePtr++; - /* Execute the byte code instruction */ - word->codeword(CodePtr); - } - /* Execution finished lets put things back the way they were */ - CodePtr = prev_code; -} - -/* Built-in Constants - *****************************************************************************/ -defconst("VERSION", version, 0, NULL, 1) -defconst("EXECDEF", execdef, 0, &version, (val_t)&docolon) -defconst("WORDSZ", wordsz, 0, &execdef, sizeof(val_t)) - -/* Built-in Variables - *****************************************************************************/ -defvar("state", state, 0, &wordsz, 0) -defvar("latest", latest, 0, &state, 0) - -/* Word Words - *****************************************************************************/ -defcode("wlink", wlink, 0, &latest){ - *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->link); -} - -defcode("wsize", wflags, 0, &wlink){ - *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->flags.attr.codesize); -} - -defcode("wname", wname, 0, &wflags){ - *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->name); -} - -defcode("wfunc", wfunc, 0, &wname){ - *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->codeword); -} - -defcode("wcode", wcode, 0, &wfunc){ - *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->code); -} - -defcode("here", here, 0, &wcode){ - ArgStack++; - *(ArgStack) = (val_t)((((word_t*)latest_val)->flags.attr.codesize) - 1); -} - -/* Interpreter Words - *****************************************************************************/ -defcode("exec", exec, 0, &here){ - word_t* word = (word_t*)(*ArgStack); - ArgStack--; - EXEC( *(word) ); -} - -defcode("find", find, 0, &exec){ - word_t const* curr = (word_t const*)latest_val; - char* name = (char*)*(ArgStack); - while(curr) - { - if (!(curr->flags.attr.hidden) && (0 == pal_strcmp(curr->name,name))) - { - break; - } - curr = curr->link; - } - *(ArgStack) = (val_t)curr; -} - -defcode("fetchtok", fetchtok, 0, &find){ - ArgStack++; - *(ArgStack) = (val_t)fetch_token(); -} - -defcode("parsetok", parsetok, 0, &fetchtok){ - char* p_str = (char*)*(ArgStack); - ArgStack++; - *(ArgStack) = (val_t)parse_token( p_str, ArgStack-1 ); - /* If the parsed token no longer needs the original string */ - if (*(ArgStack) > STRING) - { - /* Free the mem */ - pal_free(p_str); - } -} - -/* Branching and Literal Words - *****************************************************************************/ -defcode("lit", lit, 0, &parsetok){ - ArgStack++; - *(ArgStack) = *CodePtr; - CodePtr++; -} - -defcode("br", br, 0, &lit){ - CodePtr = (val_t*)(((val_t)CodePtr) + (*(CodePtr) * sizeof(val_t))); -} - -defcode("0br", zbr, 0, &br){ - if (*ArgStack == 0) - { - CodePtr = (val_t*)(((val_t)CodePtr) + (*(CodePtr) * sizeof(val_t))); - } - else - { - CodePtr++; - } - ArgStack--; -} - -/* Compiler Words - *****************************************************************************/ -defcode("ret", ret, 0, &zbr){ - CodePtr = 0; -} - -defcode("[", lbrack, 0, &ret){ - state_val = 0; -} - -defcode("]", rbrack, 1, &lbrack){ - state_val = 1; -} - -defcode("create", create, 0, &rbrack){ - /* Copy the name string */ - char* name = 0u; - if (*(ArgStack)) - { - size_t namesz = pal_strlen((char*)*(ArgStack)); - name = (char*)pal_allocate( namesz ); - pal_strcpy(name, (char*)*(ArgStack)); - } - /* Create the word entry */ - word_t* word = (word_t*)pal_allocate(sizeof(word_t)); - word->link = (word_t*)latest_val; - /* Initialize the flags (hidden and non-immediate by default) */ - word->flags.attr.immed = 0; - word->flags.attr.hidden = 1; - word->flags.attr.codesize = 1; - /* Initialize the name, codeword, and bytecode */ - word->name = name; - word->codeword = &docolon; - word->code = (val_t*)pal_allocate(sizeof(val_t)); - word->code[0] = (val_t)&ret; - /* Update Latest and Return the new word */ - latest_val = (val_t)word; - *(ArgStack) = (val_t)word; -} - -defcode(",", comma, 0, &create){ - /* Get the word we are currently compiling */ - word_t* word = (word_t*)latest_val; - /* Put the next instruction in place of the terminating 'ret' that "here" - * points too */ - word->code[word->flags.attr.codesize-1] = *(ArgStack); - ArgStack--; - /* Resize the code section and relocate if necessary */ - word->flags.attr.codesize++; - word->code = (val_t*)pal_reallocate(word->code, word->flags.attr.codesize * sizeof(val_t)); - /* Update "here" and terminate the code section */ - word->code[word->flags.attr.codesize-1] = (val_t)&ret; -} - -defcode("hidden", hidden, 1, &comma){ - ((word_t*)*(ArgStack))->flags.attr.hidden ^= 1; -} - -defcode("immediate", immediate, 1, &hidden){ - ((word_t*)*(ArgStack))->flags.attr.immed ^= 1; -} - -defcode(":", colon, 0, &immediate){ - EXEC(fetchtok); - EXEC(parsetok); - ArgStack--; - EXEC(create); - EXEC(rbrack); -} - -defcode(";", semicolon, 1, &colon){ - EXEC(lbrack); - EXEC(hidden); - ArgStack--; -} - -defcode("'", tick, 1, &semicolon){ - EXEC(fetchtok); - EXEC(parsetok); - ArgStack--; - EXEC(find); -} - -defcode("interp", interp, 0, &parsetok){ - char* p_str = NULL; - EXEC(fetchtok); - EXEC(parsetok); - /* If what we parsed was a word */ - if(*ArgStack == WORD) - { - /* Consume the type token and save off the string pointer */ - ArgStack--; - p_str = (char*)*ArgStack; - /* Search for the word in the dictionary */ - EXEC(find); - /* If we found a definition */ - if(*ArgStack) - { - /* And the definition is marked immediate or we're in immediate mode */ - if((state_val == 0) || (((word_t*)*ArgStack)->flags.attr.immed)) - { - /* Execute it */ - EXEC(exec); - } - /* Otherwise, compile it! */ - else - { - EXEC(comma); - } - } - /* We didn't find a definition */ - else - { - /* Ask the user what gives */ - pal_unknown_word(p_str); - /* Consume the token */ - ArgStack--; - } - } - /* What we parsed is a literal and we're in compile mode */ - else if (state_val == 1) - { - *(ArgStack) = (val_t)&lit; - EXEC(comma); - EXEC(comma); - } - else - { - ArgStack--; - } - - /* If we saved off a pointer, we're done with it so free the memory */ - if(p_str) pal_free(p_str); -} - -defcode("quit", quit, 0, &interp){ - while(1) - { - pal_prompt(); - EXEC(interp); - } -} - -/* Stack Manipulation Words - *****************************************************************************/ -defcode("drop", drop, 0, &tick){ - ArgStack--; -} - -defcode("swap", swap, 0, &drop){ - val_t temp = *(ArgStack); - *(ArgStack) = *(ArgStack-1); - *(ArgStack-1) = temp; -} - -defcode("dup", dup, 0, &swap){ - ArgStack++; - *(ArgStack) = *(ArgStack-1); -} - -defcode("over", over, 0, &dup){ - ArgStack++; - *(ArgStack) = *(ArgStack-2); -} - -defcode("rot", rot, 0, &over){ - val_t temp = *(ArgStack); - *(ArgStack) = *(ArgStack-1); - *(ArgStack-1) = *(ArgStack-2); - *(ArgStack-2) = temp; -} - -defcode("-rot", nrot, 0, &rot){ - val_t temp = *(ArgStack-2); - *(ArgStack-2) = *(ArgStack-1); - *(ArgStack-1) = *(ArgStack); - *(ArgStack) = temp; -} - -/* Arithmetic Words - *****************************************************************************/ -defcode("+", add, 0, &nrot){ - *(ArgStack-1) += *(ArgStack); - ArgStack--; -} - -defcode("-", sub, 0, &add){ - *(ArgStack-1) -= *(ArgStack); - ArgStack--; -} - -defcode("*", mul, 0, &sub){ - *(ArgStack-1) *= *(ArgStack); - ArgStack--; -} - -defcode("/", div, 0, &mul){ - *(ArgStack-1) /= *(ArgStack); - ArgStack--; -} - -defcode("%", mod, 0, &div){ - *(ArgStack-1) %= *(ArgStack); - ArgStack--; -} - -/* Boolean Conditional Words - *****************************************************************************/ -defcode("=", equal, 0, &mod){ - *(ArgStack-1) = *(ArgStack-1) == *(ArgStack); - ArgStack--; -} - -defcode("!=", notequal, 0, &equal){ - *(ArgStack-1) = *(ArgStack-1) != *(ArgStack); - ArgStack--; -} - -defcode("<", lessthan, 0, ¬equal){ - *(ArgStack-1) = *(ArgStack-1) < *(ArgStack); - ArgStack--; -} - -defcode(">", greaterthan, 0, &lessthan){ - *(ArgStack-1) = *(ArgStack-1) > *(ArgStack); - ArgStack--; -} - -defcode("<=", lessthaneq, 0, &greaterthan){ - *(ArgStack-1) = *(ArgStack-1) <= *(ArgStack); - ArgStack--; -} - -defcode(">=", greaterthaneq, 0, &lessthaneq){ - *(ArgStack-1) = *(ArgStack-1) >= *(ArgStack); - ArgStack--; -} - -defcode("and", and, 0, &greaterthaneq){ - *(ArgStack-1) = *(ArgStack-1) && *(ArgStack); - ArgStack--; -} - -defcode("or", or, 0, &and){ - *(ArgStack-1) = *(ArgStack-1) || *(ArgStack); - ArgStack--; -} - -defcode("not", not, 0, &or){ - *(ArgStack) = !(*(ArgStack)); -} - -/* Bitwise Words - *****************************************************************************/ -defcode("band", band, 0, ¬){ - *(ArgStack-1) = *(ArgStack-1) & *(ArgStack); - ArgStack--; -} - -defcode("bor", bor, 0, &band){ - *(ArgStack-1) = *(ArgStack-1) | *(ArgStack); - ArgStack--; -} - -defcode("bxor", bxor, 0, &bor){ - *(ArgStack-1) = *(ArgStack-1) ^ *(ArgStack); - ArgStack--; -} - -defcode("bnot", bnot, 0, &bxor){ - *(ArgStack) = ~(*(ArgStack)); -} - -/* Memory Manipulation Words - *****************************************************************************/ -defcode("!", store, 0, &bnot){ - *((val_t*)*(ArgStack)) = *(ArgStack-1); - ArgStack -= 2; -} - -defcode("@", fetch, 0, &store){ - *(ArgStack) = *((val_t*)*(ArgStack)); -} - -defcode("+!", addstore, 0, &fetch){ - *((val_t*)*(ArgStack)) += *(ArgStack-1); - ArgStack -= 2; -} - -defcode("-!", substore, 0, &addstore){ - *((val_t*)*(ArgStack)) -= *(ArgStack-1); - ArgStack -= 2; -} - -defcode("b!", bytestore, 0, &substore){ - *((char*)*(ArgStack)) = (char)*(ArgStack-1); - ArgStack -= 2; -} - -defcode("b@", bytefetch, 0, &bytestore){ - *(ArgStack) = *((char*)*(ArgStack)); -} - -defcode("b@b!", bytecopy, 0, &bytefetch){ -} - -defcode("bmove", bytemove, 0, &bytecopy){ -} - -int main(int argc, char** argv) -{ - (void)argc; - (void)argv; - /* Compile-time Assertions */ - CT_ASSERT(sizeof(val_t) == sizeof(val_t*)); - CT_ASSERT(sizeof(val_t) == sizeof(flags_t)); - - /* Platform specific initialization */ - latest_val = (val_t)&bytemove; - - /* Start the interpreter */ - EXEC(quit); - return 0; -} - -/* Debugging Words - *****************************************************************************/ -#if 0 -defcode("printw", printw, 0, &mem_free){ - word_t* word = (word_t*)*(ArgStack); - val_t* bytecode = word->code; - ArgStack--; - - printf("Name: %s\n", word->name); - //printf("Flags: 0x%lX\n", word->flags); - if (word->codeword == &docolon) - { - puts("CodeFn: docolon"); - puts("Bytecode:"); - while(bytecode) - { - if (*bytecode == (val_t)&literal) - { - bytecode++; - printf("\tlit %ld\n", *bytecode); - } - else if (*bytecode == (val_t)&zbranch) - { - bytecode++; - printf("\t0br %ld\n", *bytecode); - } - else if (*bytecode == (val_t)&branch) - { - bytecode++; - printf("\tbr %ld\n", *bytecode); - } - else - { - printf("\t%s\n", ((word_t*) *bytecode)->name); - } - - if (*bytecode == (val_t)&ret) - { - bytecode = 0; - break; - } - else - { - bytecode++; - } - } - } - else - { - printf("CodeFn: 0x%lX\n",(val_t)word->codeword); - printf("Bytecode: (native)\n"); - } -} - -defcode("printallw", printallw, 0, &printw){ - const word_t* word = (word_t*)latest_val; - while(word) - { - puts(word->name); - word = word->link; - } -} - -defcode("printdefw", printdefw, 0, &printallw){ - const word_t* word = (word_t*)latest_val; - while(word != &printdefw) - { - printf("%s\t%ld %ld", - word->name, - word->flags.attr.immed, - word->flags.attr.hidden); - word = word->link; - } -} -#endif - +#include "slvm.h" +#include "parser.h" +#include "pal.h" + +/* + Wish List: + + * Dynamic Loading and Unloading of Dictionaries (File, Object, or Dynamic Lib) + * Rework w* words to allow gettign and setting attributes of a word + * Add optional debugging words + * Add optional floating point / fixed point words + * Add optional runtime integrity checks + * Add optional static heap replacement for malloc, realloc, free + * Add optional support for embedded systems (No dependence on stdlib) + * Run through profiler and optimize execution speed where possible. + * Add optional support for temporaries + * Add optional code optimizer for compiled words + * Add ability to compile to simple object file + * Add ability to compile to shared library + * Add ability to compile to standalone executable + * Add support for multi-tasking + * Add support for multi-tasking with multiple cores/threads + +*/ + +/* Inner Interpreter + *****************************************************************************/ +void docolon(val_t* code) { + word_t* word; + /* We may have previously been executing a word so we should save off our + * previous position */ + val_t* prev_code = CodePtr; + /* Set the next instruction to execute */ + CodePtr = code; + /* Loop through until "ret" sets the code pointer to null */ + while(CodePtr) + { + word = (word_t*)*CodePtr; + /* Increment the instruction pointer */ + CodePtr++; + /* Execute the byte code instruction */ + word->codeword(CodePtr); + } + /* Execution finished lets put things back the way they were */ + CodePtr = prev_code; +} + +/* Built-in Constants + *****************************************************************************/ +defconst("VERSION", version, 0, NULL, 1) +defconst("EXECDEF", execdef, 0, &version, (val_t)&docolon) +defconst("WORDSZ", wordsz, 0, &execdef, sizeof(val_t)) + +/* Built-in Variables + *****************************************************************************/ +defvar("state", state, 0, &wordsz, 0) +defvar("latest", latest, 0, &state, 0) + +/* Word Words + *****************************************************************************/ +defcode("wlink", wlink, 0, &latest){ + *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->link); +} + +defcode("wsize", wflags, 0, &wlink){ + *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->flags.attr.codesize); +} + +defcode("wname", wname, 0, &wflags){ + *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->name); +} + +defcode("wfunc", wfunc, 0, &wname){ + *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->codeword); +} + +defcode("wcode", wcode, 0, &wfunc){ + *(ArgStack) = (val_t)(((word_t*)*(ArgStack))->code); +} + +defcode("here", here, 0, &wcode){ + ArgStack++; + *(ArgStack) = (val_t)((((word_t*)latest_val)->flags.attr.codesize) - 1); +} + +/* Interpreter Words + *****************************************************************************/ +defcode("exec", exec, 0, &here){ + word_t* word = (word_t*)(*ArgStack); + ArgStack--; + EXEC( *(word) ); +} + +defcode("find", find, 0, &exec){ + word_t const* curr = (word_t const*)latest_val; + char* name = (char*)*(ArgStack); + while(curr) + { + if (!(curr->flags.attr.hidden) && (0 == pal_strcmp(curr->name,name))) + { + break; + } + curr = curr->link; + } + *(ArgStack) = (val_t)curr; +} + +defcode("fetchtok", fetchtok, 0, &find){ + ArgStack++; + *(ArgStack) = (val_t)fetch_token(); +} + +defcode("parsetok", parsetok, 0, &fetchtok){ + char* p_str = (char*)*(ArgStack); + ArgStack++; + *(ArgStack) = (val_t)parse_token( p_str, ArgStack-1 ); + /* If the parsed token no longer needs the original string */ + if (*(ArgStack) > STRING) + { + /* Free the mem */ + pal_free(p_str); + } +} + +/* Branching and Literal Words + *****************************************************************************/ +defcode("lit", lit, 0, &parsetok){ + ArgStack++; + *(ArgStack) = *CodePtr; + CodePtr++; +} + +defcode("br", br, 0, &lit){ + CodePtr = (val_t*)(((val_t)CodePtr) + (*(CodePtr) * sizeof(val_t))); +} + +defcode("0br", zbr, 0, &br){ + if (*ArgStack == 0) + { + CodePtr = (val_t*)(((val_t)CodePtr) + (*(CodePtr) * sizeof(val_t))); + } + else + { + CodePtr++; + } + ArgStack--; +} + +/* Compiler Words + *****************************************************************************/ +defcode("ret", ret, 0, &zbr){ + CodePtr = 0; +} + +defcode("[", lbrack, 0, &ret){ + state_val = 0; +} + +defcode("]", rbrack, 1, &lbrack){ + state_val = 1; +} + +defcode("create", create, 0, &rbrack){ + /* Copy the name string */ + char* name = 0u; + if (*(ArgStack)) + { + size_t namesz = pal_strlen((char*)*(ArgStack)); + name = (char*)pal_allocate( namesz ); + pal_strcpy(name, (char*)*(ArgStack)); + } + /* Create the word entry */ + word_t* word = (word_t*)pal_allocate(sizeof(word_t)); + word->link = (word_t*)latest_val; + /* Initialize the flags (hidden and non-immediate by default) */ + word->flags.attr.immed = 0; + word->flags.attr.hidden = 1; + word->flags.attr.codesize = 1; + /* Initialize the name, codeword, and bytecode */ + word->name = name; + word->codeword = &docolon; + word->code = (val_t*)pal_allocate(sizeof(val_t)); + word->code[0] = (val_t)&ret; + /* Update Latest and Return the new word */ + latest_val = (val_t)word; + *(ArgStack) = (val_t)word; +} + +defcode(",", comma, 0, &create){ + /* Get the word we are currently compiling */ + word_t* word = (word_t*)latest_val; + /* Put the next instruction in place of the terminating 'ret' that "here" + * points too */ + word->code[word->flags.attr.codesize-1] = *(ArgStack); + ArgStack--; + /* Resize the code section and relocate if necessary */ + word->flags.attr.codesize++; + word->code = (val_t*)pal_reallocate(word->code, word->flags.attr.codesize * sizeof(val_t)); + /* Update "here" and terminate the code section */ + word->code[word->flags.attr.codesize-1] = (val_t)&ret; +} + +defcode("hidden", hidden, 1, &comma){ + ((word_t*)*(ArgStack))->flags.attr.hidden ^= 1; +} + +defcode("immediate", immediate, 1, &hidden){ + ((word_t*)*(ArgStack))->flags.attr.immed ^= 1; +} + +defcode(":", colon, 0, &immediate){ + EXEC(fetchtok); + EXEC(parsetok); + ArgStack--; + EXEC(create); + EXEC(rbrack); +} + +defcode(";", semicolon, 1, &colon){ + EXEC(lbrack); + EXEC(hidden); + ArgStack--; +} + +defcode("'", tick, 1, &semicolon){ + EXEC(fetchtok); + EXEC(parsetok); + ArgStack--; + EXEC(find); +} + +defcode("interp", interp, 0, &parsetok){ + char* p_str = NULL; + EXEC(fetchtok); + EXEC(parsetok); + /* If what we parsed was a word */ + if(*ArgStack == WORD) + { + /* Consume the type token and save off the string pointer */ + ArgStack--; + p_str = (char*)*ArgStack; + /* Search for the word in the dictionary */ + EXEC(find); + /* If we found a definition */ + if(*ArgStack) + { + /* And the definition is marked immediate or we're in immediate mode */ + if((state_val == 0) || (((word_t*)*ArgStack)->flags.attr.immed)) + { + /* Execute it */ + EXEC(exec); + } + /* Otherwise, compile it! */ + else + { + EXEC(comma); + } + } + /* We didn't find a definition */ + else + { + /* Ask the user what gives */ + pal_unknown_word(p_str); + /* Consume the token */ + ArgStack--; + } + } + /* What we parsed is a literal and we're in compile mode */ + else if (state_val == 1) + { + *(ArgStack) = (val_t)&lit; + EXEC(comma); + EXEC(comma); + } + else + { + ArgStack--; + } + + /* If we saved off a pointer, we're done with it so free the memory */ + if(p_str) pal_free(p_str); +} + +defcode("quit", quit, 0, &interp){ + while(1) + { + pal_prompt(); + EXEC(interp); + } +} + +/* Stack Manipulation Words + *****************************************************************************/ +defcode("drop", drop, 0, &tick){ + ArgStack--; +} + +defcode("swap", swap, 0, &drop){ + val_t temp = *(ArgStack); + *(ArgStack) = *(ArgStack-1); + *(ArgStack-1) = temp; +} + +defcode("dup", dup, 0, &swap){ + ArgStack++; + *(ArgStack) = *(ArgStack-1); +} + +defcode("over", over, 0, &dup){ + ArgStack++; + *(ArgStack) = *(ArgStack-2); +} + +defcode("rot", rot, 0, &over){ + val_t temp = *(ArgStack); + *(ArgStack) = *(ArgStack-1); + *(ArgStack-1) = *(ArgStack-2); + *(ArgStack-2) = temp; +} + +defcode("-rot", nrot, 0, &rot){ + val_t temp = *(ArgStack-2); + *(ArgStack-2) = *(ArgStack-1); + *(ArgStack-1) = *(ArgStack); + *(ArgStack) = temp; +} + +/* Arithmetic Words + *****************************************************************************/ +defcode("+", add, 0, &nrot){ + *(ArgStack-1) += *(ArgStack); + ArgStack--; +} + +defcode("-", sub, 0, &add){ + *(ArgStack-1) -= *(ArgStack); + ArgStack--; +} + +defcode("*", mul, 0, &sub){ + *(ArgStack-1) *= *(ArgStack); + ArgStack--; +} + +defcode("/", div, 0, &mul){ + *(ArgStack-1) /= *(ArgStack); + ArgStack--; +} + +defcode("%", mod, 0, &div){ + *(ArgStack-1) %= *(ArgStack); + ArgStack--; +} + +/* Boolean Conditional Words + *****************************************************************************/ +defcode("=", equal, 0, &mod){ + *(ArgStack-1) = *(ArgStack-1) == *(ArgStack); + ArgStack--; +} + +defcode("!=", notequal, 0, &equal){ + *(ArgStack-1) = *(ArgStack-1) != *(ArgStack); + ArgStack--; +} + +defcode("<", lessthan, 0, ¬equal){ + *(ArgStack-1) = *(ArgStack-1) < *(ArgStack); + ArgStack--; +} + +defcode(">", greaterthan, 0, &lessthan){ + *(ArgStack-1) = *(ArgStack-1) > *(ArgStack); + ArgStack--; +} + +defcode("<=", lessthaneq, 0, &greaterthan){ + *(ArgStack-1) = *(ArgStack-1) <= *(ArgStack); + ArgStack--; +} + +defcode(">=", greaterthaneq, 0, &lessthaneq){ + *(ArgStack-1) = *(ArgStack-1) >= *(ArgStack); + ArgStack--; +} + +defcode("and", and, 0, &greaterthaneq){ + *(ArgStack-1) = *(ArgStack-1) && *(ArgStack); + ArgStack--; +} + +defcode("or", or, 0, &and){ + *(ArgStack-1) = *(ArgStack-1) || *(ArgStack); + ArgStack--; +} + +defcode("not", not, 0, &or){ + *(ArgStack) = !(*(ArgStack)); +} + +/* Bitwise Words + *****************************************************************************/ +defcode("band", band, 0, ¬){ + *(ArgStack-1) = *(ArgStack-1) & *(ArgStack); + ArgStack--; +} + +defcode("bor", bor, 0, &band){ + *(ArgStack-1) = *(ArgStack-1) | *(ArgStack); + ArgStack--; +} + +defcode("bxor", bxor, 0, &bor){ + *(ArgStack-1) = *(ArgStack-1) ^ *(ArgStack); + ArgStack--; +} + +defcode("bnot", bnot, 0, &bxor){ + *(ArgStack) = ~(*(ArgStack)); +} + +/* Memory Manipulation Words + *****************************************************************************/ +defcode("!", store, 0, &bnot){ + *((val_t*)*(ArgStack)) = *(ArgStack-1); + ArgStack -= 2; +} + +defcode("@", fetch, 0, &store){ + *(ArgStack) = *((val_t*)*(ArgStack)); +} + +defcode("+!", addstore, 0, &fetch){ + *((val_t*)*(ArgStack)) += *(ArgStack-1); + ArgStack -= 2; +} + +defcode("-!", substore, 0, &addstore){ + *((val_t*)*(ArgStack)) -= *(ArgStack-1); + ArgStack -= 2; +} + +defcode("b!", bytestore, 0, &substore){ + *((char*)*(ArgStack)) = (char)*(ArgStack-1); + ArgStack -= 2; +} + +defcode("b@", bytefetch, 0, &bytestore){ + *(ArgStack) = *((char*)*(ArgStack)); +} + +defcode("b@b!", bytecopy, 0, &bytefetch){ +} + +defcode("bmove", bytemove, 0, &bytecopy){ +} + +int main(int argc, char** argv) +{ + (void)argc; + (void)argv; + /* Compile-time Assertions */ + CT_ASSERT(sizeof(val_t) == sizeof(val_t*)); + CT_ASSERT(sizeof(val_t) == sizeof(flags_t)); + + /* Platform specific initialization */ + latest_val = (val_t)&bytemove; + + /* Start the interpreter */ + EXEC(quit); + return 0; +} + +/* Debugging Words + *****************************************************************************/ +#if 0 +defcode("printw", printw, 0, &mem_free){ + word_t* word = (word_t*)*(ArgStack); + val_t* bytecode = word->code; + ArgStack--; + + printf("Name: %s\n", word->name); + //printf("Flags: 0x%lX\n", word->flags); + if (word->codeword == &docolon) + { + puts("CodeFn: docolon"); + puts("Bytecode:"); + while(bytecode) + { + if (*bytecode == (val_t)&literal) + { + bytecode++; + printf("\tlit %ld\n", *bytecode); + } + else if (*bytecode == (val_t)&zbranch) + { + bytecode++; + printf("\t0br %ld\n", *bytecode); + } + else if (*bytecode == (val_t)&branch) + { + bytecode++; + printf("\tbr %ld\n", *bytecode); + } + else + { + printf("\t%s\n", ((word_t*) *bytecode)->name); + } + + if (*bytecode == (val_t)&ret) + { + bytecode = 0; + break; + } + else + { + bytecode++; + } + } + } + else + { + printf("CodeFn: 0x%lX\n",(val_t)word->codeword); + printf("Bytecode: (native)\n"); + } +} + +defcode("printallw", printallw, 0, &printw){ + const word_t* word = (word_t*)latest_val; + while(word) + { + puts(word->name); + word = word->link; + } +} + +defcode("printdefw", printdefw, 0, &printallw){ + const word_t* word = (word_t*)latest_val; + while(word != &printdefw) + { + printf("%s\t%ld %ld", + word->name, + word->flags.attr.immed, + word->flags.attr.hidden); + word = word->link; + } +} +#endif + -- 2.52.0