]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Added specs to test the CLI
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 28 Oct 2014 02:08:02 +0000 (22:08 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 28 Oct 2014 02:08:02 +0000 (22:08 -0400)
source/sclpl/main.c
source/sclpl/pprint.c
spec/cli_spec.rb [new file with mode: 0644]
spec/spec_helper.rb
spec/src/sample.scl [new file with mode: 0644]

index 17b36066a53e74c067de263765c0d20fda37afc7..885e3dceafd3f3b8c0e41678a35ff73ed7f32344 100644 (file)
@@ -163,6 +163,8 @@ str_t* str_join(char* joinstr, vec_t* strs) {
 /* Utility Functions
  *****************************************************************************/
 typedef enum {
+    TOKFILE,
+    ASTFILE,
     CSOURCE,
     OBJECT,
     PROGRAM,
@@ -173,6 +175,8 @@ typedef enum {
 str_t* get_extension(file_type_t ftype) {
     str_t* ext = NULL;
     switch (ftype) {
+        case TOKFILE:   ext = str_new(".tok");   break;
+        case ASTFILE:   ext = str_new(".ast");   break;
         case CSOURCE:   ext = str_new(".c");   break;
         case OBJECT:    ext = str_new(".o");   break;
         case PROGRAM:   ext = str_new("");     break;
@@ -196,10 +200,10 @@ str_t* get_filename(file_type_t ftype, str_t* infile) {
 }
 
 vec_t* parse_file(str_t* in) {
+    bool failed = false;
     FILE* input = (NULL == in) ? stdin : fopen(str_cstr(in), "r");
     parser_t* p_parser = parser_new(NULL, input);
     vec_t* p_vec = vec_new(0);
-    bool failed = false;
     while(!parser_eof(p_parser)) {
         tree_t* p_tree = grammar_toplevel(p_parser);
         if (NULL != p_tree) {
@@ -216,6 +220,59 @@ vec_t* parse_file(str_t* in) {
     return ((failed) ? NULL : p_vec);
 }
 
+vec_t* program_deps(vec_t* program) {
+    vec_t* deps = vec_new(0);
+    (void)program;
+    return deps;
+}
+
+str_t* token_file(str_t* in) {
+    str_t* ofname = NULL;
+    FILE* input = (NULL == in) ? stdin : fopen(str_cstr(in), "r");
+    FILE* output;
+    if (NULL == in) {
+        output = stdout;
+    } else {
+        ofname = get_filename(TOKFILE, in);
+        output = fopen(str_cstr(ofname), "w");
+    }
+
+    lexer_t* p_lexer = lexer_new(NULL, input);
+    lex_tok_t* token;
+    while(NULL != (token = lexer_read(p_lexer))) {
+        pprint_token(output, token);
+        mem_release(token);
+    }
+    mem_release(p_lexer);
+
+    return ofname;
+}
+
+str_t* syntax_file(str_t* in) {
+    str_t* ofname = NULL;
+    FILE* output;
+    if (NULL == in) {
+        output = stdout;
+    } else {
+        ofname = get_filename(ASTFILE, in);
+        output = fopen(str_cstr(ofname), "w");
+    }
+    vec_t* program = parse_file(in);
+    if (NULL != program) {
+        for (size_t idx = 0; idx < vec_size(program); idx++) {
+            pprint_tree(output, (tree_t*)vec_at(program, idx), 0);
+        }
+        mem_release(program);
+        fclose(output);
+    } else {
+        fclose(output);
+        remove(str_cstr(ofname));
+        mem_release(ofname);
+        ofname = NULL;
+    }
+    return ofname;
+}
+
 str_t* translate_file(str_t* in) {
     str_t* ofname = NULL;
     FILE* output;
@@ -258,32 +315,34 @@ str_t* link_files(list_t* in) {
 /* Driver Modes
  *****************************************************************************/
 static int emit_tokens(void) {
-    lexer_t* p_lexer = lexer_new(NULL, stdin);
-    lex_tok_t* token;
-    while(NULL != (token = lexer_read(p_lexer))) {
-        pprint_token(stdout, token);
-        mem_release(token);
+    list_t* files  = input_files();
+    size_t  nfiles = list_size(files);
+    if (0 == nfiles) {
+        (void)token_file(NULL);
+    } else if (1 == nfiles) {
+        str_t* fname = list_front(files)->contents;
+        mem_release( token_file(fname) );
+    } else {
+        error_msg("too many files provided for target mode 'tokens'");
     }
-    mem_release(p_lexer);
+    mem_release(files);
     return 0;
 }
 
 static int emit_tree(void) {
     int ret = 0;
-    parser_t* p_parser = parser_new(NULL, stdin);
-    while(!parser_eof(p_parser)) {
-        tree_t* p_tree = grammar_toplevel(p_parser);
-        if (NULL != p_tree) {
-            tree_t* p_ast = convert_to_ast(p_tree);
-            pprint_tree(stdout, p_ast, 0);
-            mem_release(p_tree);
-            mem_release(p_ast);
-        } else {
-            parser_resume(p_parser);
-            ret = 1;
-        }
+    list_t* files  = input_files();
+    size_t  nfiles = list_size(files);
+    if (0 == nfiles) {
+        (void)syntax_file(NULL);
+    } else if (1 == nfiles) {
+        str_t* fname = list_front(files)->contents;
+        mem_release( syntax_file(fname) );
+    } else {
+        error_msg("too many files provided for target mode 'ast'");
     }
-    mem_release(p_parser);
+    mem_release(files);
+
     return ret;
 }
 
index b6f9758b5d054831ae989273311bd8d5bc07c8c1..6d51eab93526e92a51220e161a749b7083946232 100644 (file)
@@ -59,13 +59,13 @@ void pprint_token_type(FILE* file, lex_tok_t* token) {
 void pprint_token_value(FILE* file, lex_tok_t* token) {
     void* value = token->value;
     switch(token->type) {
-        case T_STRING: fprintf(file, "\"%s\"", ((char*)value));            break;
-        case T_CHAR:   print_char(file, ((char)(int)value));               break;
-        case T_INT:    fprintf(file, "%ld",  *((long int*)value));         break;
-        case T_FLOAT:  fprintf(file, "%f",   *((double*)value));           break;
-        case T_BOOL:   fprintf(file, "%s",   ((int)value)?"true":"false"); break;
-        case T_VAR:    fprintf(file, "%s",   ((char*)value));              break;
-        default:       fprintf(file, "???");                               break;
+        case T_STRING: fprintf(file, "\"%s\"", ((char*)value));                 break;
+        case T_CHAR:   print_char(file, ((char)(intptr_t)value));               break;
+        case T_INT:    fprintf(file, "%ld",  *((long int*)value));              break;
+        case T_FLOAT:  fprintf(file, "%f",   *((double*)value));                break;
+        case T_BOOL:   fprintf(file, "%s",   ((intptr_t)value)?"true":"false"); break;
+        case T_VAR:    fprintf(file, "%s",   ((char*)value));                   break;
+        default:       fprintf(file, "???");                                    break;
     }
 }
 
@@ -86,13 +86,13 @@ void pprint_tree(FILE* file, tree_t* tree, int depth)
     if (tree->tag == ATOM) {
         pprint_token(file, tree->ptr.tok);
     } else {
-        puts("(tree");
+        fputs("(tree", file);
         vec_t* p_vec = tree->ptr.vec;
         for(size_t idx = 0; idx < vec_size(p_vec); idx++) {
             pprint_tree(file, (tree_t*)vec_at(p_vec, idx), depth+1);
         }
         print_indent(file, depth);
-        puts(")");
+        fputs(")\n", file);
     }
 }
 
diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb
new file mode 100644 (file)
index 0000000..e4a4480
--- /dev/null
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe "cli" do
+  context "token mode" do
+    it "should accept input from stdin" do
+      expect(cli(['--tokens'])).to eq("")
+    end
+
+    it "should translate the input file" do
+      expect(cli(['--tokens', 'spec/src/sample.scl'])).to eq("")
+      expect(File.exists? 'spec/src/sample.tok').to be(true)
+      FileUtils.rm('spec/src/sample.tok')
+    end
+  end
+
+  context "ast mode" do
+    it "should accept input from stdin" do
+      expect(cli(['--ast'])).to eq("")
+    end
+
+    it "should translate the input file" do
+      expect(cli(['--ast', 'spec/src/sample.scl'])).to eq("")
+      expect(File.exists? 'spec/src/sample.ast').to be(true)
+      FileUtils.rm('spec/src/sample.ast')
+    end
+  end
+
+  context "c source mode" do
+    it "should accept input from stdin" do
+      expect(cli(['--csource'])).not_to eq("")
+    end
+
+    it "should translate the input file" do
+      expect(cli(['--csource', 'spec/src/sample.scl'])).to eq("")
+      expect(File.exists? 'spec/src/sample.c').to be(true)
+      FileUtils.rm('spec/src/sample.c')
+    end
+  end
+
+  context "object mode" do
+    it "should error when too few input files provided" do
+      expect{cli(['--object'])}.to raise_error(/too few files/)
+    end
+
+    it "should error when too many input files provided" do
+      expect{cli(['--object', 'spec/src/sample.scl', 'spec/src/sample.scl'])}.to raise_error(/too many files/)
+    end
+
+    it "should compile the input file in verbose mode (short flag)" do
+      pending "Can't find the sclpl header"
+      expect(cli(['-v', '--object', 'spec/src/sample.scl'])).to eq(
+          "clang -c -o spec/src/sample.o spec/src/sample.c")
+      expect(File.exists? 'spec/src/sample.o').to be(true)
+      FileUtils.rm('spec/src/sample.o')
+    end
+
+    it "should compile the input file in verbose mode (long flag)" do
+      pending "Can't find the sclpl header"
+      expect(cli(['--verbose', '--object', 'spec/src/sample.scl'])).to eq(
+          "clang -c -o spec/src/sample.o spec/src/sample.c")
+      expect(File.exists? 'spec/src/sample.o').to be(true)
+      FileUtils.rm('spec/src/sample.o')
+    end
+
+    it "should compile the input file" do
+      pending "Can't find the sclpl header"
+      expect(cli(['--object', 'spec/src/sample.scl'])).to eq("")
+      expect(File.exists? 'spec/src/sample.o').to be(true)
+      FileUtils.rm('spec/src/sample.o')
+    end
+  end
+end
+
index ea3dcaacdb53dd213efa7f84a35720d8c30176f8..409f27a33715acbb4c2113578aa0d3fc4fd3b88f 100644 (file)
@@ -1,10 +1,15 @@
 require 'open3'
 
-def lexer(input)
-  out, err, status = Open3.capture3('./build/bin/sclpl-test', '--tokens', :stdin_data => input)
-  raise "Lexer command returned non-zero status" unless status.success?
+def cli(options, input = "")
+  out, err, status = Open3.capture3(
+      *(['./build/bin/sclpl-test'] + options + [{:stdin_data => input}]))
   raise err unless err == ""
-  out.scan(/^(T_[A-Z]+(:("[^"]*"|[^\n]+))?)/m).map {|m| m[0] }
+  raise "Command returned non-zero status" unless status.success?
+  out
+end
+
+def lexer(input)
+  cli(['--tokens'], input).scan(/^(T_[A-Z]+(:("[^"]*"|[^\n]+))?)/m).map {|m| m[0] }
 end
 
 def re_structure( token_array, offset = 0 )
@@ -25,9 +30,7 @@ def re_structure( token_array, offset = 0 )
 end
 
 def ast(input)
-  out, err, status = Open3.capture3('./build/bin/sclpl-test', '--ast', :stdin_data => input)
-  raise err unless err == ""
-  raise "Parser command returned non-zero status" unless status.success?
+  out = cli(['--ast'], input)
   # Prep the parens for reading
   out.gsub!(/([()])|tree/,' \1 ')
   # Replace string literals so we can tokenize on spaces
@@ -50,8 +53,5 @@ def ast(input)
 end
 
 def ccode(input)
-  out, err, status = Open3.capture3('./build/bin/sclpl-test', '--csource', :stdin_data => input)
-  raise err unless err == ""
-  raise "Parser command returned non-zero status" unless status.success?
-  out
+  cli(['--csource'], input)
 end
diff --git a/spec/src/sample.scl b/spec/src/sample.scl
new file mode 100644 (file)
index 0000000..e69de29