sfrp 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags +3 -0
  3. data/.editorconfig +9 -0
  4. data/.gitignore +14 -0
  5. data/.rubocop.yml +629 -0
  6. data/.travis.yml +12 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +28 -0
  9. data/README.md +34 -0
  10. data/Rakefile +1 -0
  11. data/base-library/Base.sfrp +81 -0
  12. data/base-library/IO/AVR/ATMEGA8.c +9 -0
  13. data/base-library/IO/AVR/ATMEGA8.h +6 -0
  14. data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
  15. data/base-library/IO/STDIO.c +40 -0
  16. data/base-library/IO/STDIO.h +13 -0
  17. data/base-library/IO/STDIO.sfrp +10 -0
  18. data/bin/sfrp +7 -0
  19. data/lib/sfrp.rb +2 -0
  20. data/lib/sfrp/command.rb +73 -0
  21. data/lib/sfrp/compiler.rb +94 -0
  22. data/lib/sfrp/error.rb +4 -0
  23. data/lib/sfrp/file.rb +18 -0
  24. data/lib/sfrp/flat/dsl.rb +33 -0
  25. data/lib/sfrp/flat/elements.rb +90 -0
  26. data/lib/sfrp/flat/exception.rb +45 -0
  27. data/lib/sfrp/flat/expression.rb +125 -0
  28. data/lib/sfrp/flat/set.rb +61 -0
  29. data/lib/sfrp/input/exception.rb +16 -0
  30. data/lib/sfrp/input/parser.rb +417 -0
  31. data/lib/sfrp/input/set.rb +29 -0
  32. data/lib/sfrp/input/transformer.rb +219 -0
  33. data/lib/sfrp/low/dsl.rb +126 -0
  34. data/lib/sfrp/low/element.rb +126 -0
  35. data/lib/sfrp/low/set.rb +62 -0
  36. data/lib/sfrp/mono/dsl.rb +120 -0
  37. data/lib/sfrp/mono/environment.rb +26 -0
  38. data/lib/sfrp/mono/exception.rb +21 -0
  39. data/lib/sfrp/mono/expression.rb +124 -0
  40. data/lib/sfrp/mono/function.rb +86 -0
  41. data/lib/sfrp/mono/memory.rb +32 -0
  42. data/lib/sfrp/mono/node.rb +125 -0
  43. data/lib/sfrp/mono/pattern.rb +69 -0
  44. data/lib/sfrp/mono/set.rb +151 -0
  45. data/lib/sfrp/mono/type.rb +210 -0
  46. data/lib/sfrp/mono/vconst.rb +134 -0
  47. data/lib/sfrp/output/set.rb +33 -0
  48. data/lib/sfrp/poly/dsl.rb +171 -0
  49. data/lib/sfrp/poly/elements.rb +168 -0
  50. data/lib/sfrp/poly/exception.rb +42 -0
  51. data/lib/sfrp/poly/expression.rb +170 -0
  52. data/lib/sfrp/poly/monofier.rb +73 -0
  53. data/lib/sfrp/poly/set.rb +90 -0
  54. data/lib/sfrp/poly/typing.rb +197 -0
  55. data/lib/sfrp/raw/dsl.rb +41 -0
  56. data/lib/sfrp/raw/elements.rb +164 -0
  57. data/lib/sfrp/raw/exception.rb +40 -0
  58. data/lib/sfrp/raw/expression.rb +168 -0
  59. data/lib/sfrp/raw/namespace.rb +30 -0
  60. data/lib/sfrp/raw/set.rb +109 -0
  61. data/lib/sfrp/version.rb +3 -0
  62. data/sfrp.gemspec +40 -0
  63. data/spec/sfrp/Test.sfrp +4 -0
  64. data/spec/sfrp/compiler_spec.rb +17 -0
  65. data/spec/sfrp/flat/set_spec.rb +40 -0
  66. data/spec/sfrp/input/parse_test.sfrp +20 -0
  67. data/spec/sfrp/input/set_spec.rb +18 -0
  68. data/spec/sfrp/low/set_spec.rb +20 -0
  69. data/spec/sfrp/mono/expected.yml +295 -0
  70. data/spec/sfrp/mono/set_spec.rb +152 -0
  71. data/spec/sfrp/output/set_spec.rb +29 -0
  72. data/spec/sfrp/poly/set_spec.rb +290 -0
  73. data/spec/sfrp/raw/set_spec.rb +38 -0
  74. data/spec/spec_helper.rb +16 -0
  75. data/test/IntTest/Main.c +5 -0
  76. data/test/IntTest/Main.h +6 -0
  77. data/test/IntTest/Main.sfrp +10 -0
  78. data/test/IntTest/in.txt +3 -0
  79. data/test/IntTest/out.txt +4 -0
  80. data/test/MaybeTest/Main.sfrp +8 -0
  81. data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
  82. data/test/MaybeTest/in.txt +6 -0
  83. data/test/MaybeTest/out.txt +6 -0
  84. data/test/Rakefile +15 -0
  85. metadata +290 -0
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.1
5
+ - 2.0
6
+ install:
7
+ - gem install bundler
8
+ script:
9
+ - 'bundle install'
10
+ - 'bundle exec rspec'
11
+ - 'bundle exec rubocop'
12
+ - 'cd test; rake'
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (c) 2016, Kensuke Sawada
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
+ COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ SFRP
2
+ =====
3
+
4
+ Pure Functional Language for microcontrollers.
5
+
6
+ [![Build Status](https://travis-ci.org/sfrp/sfrp.svg?branch=master)](https://travis-ci.org/sfrp/sfrp)
7
+ [![Coverage Status](https://coveralls.io/repos/github/sfrp/sfrp/badge.svg?branch=master)](https://coveralls.io/github/sfrp/sfrp?branch=master)
8
+
9
+ # Install SFRP
10
+ ```
11
+ $ git clone https://github.com/sfrp/sfrp.git ~/sfrp
12
+ $ cd ~/sfrp
13
+ $ rake install
14
+ ```
15
+ For updating, `git pull && rake install`.
16
+
17
+ # Usage Example
18
+ Write following simple accumulator program.
19
+ ```
20
+ -- Main.sfrp
21
+ import Base
22
+ import IO.STDIO as IO
23
+
24
+ in @x from IO.$getInt()
25
+ out IO.$putInt(@y)
26
+
27
+ @y 0 = @x + @@y
28
+ ```
29
+
30
+ Compile and Run the program.
31
+ ```
32
+ $ sfrp Main --build=cc
33
+ $ ./Main
34
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,81 @@
1
+ ptype Int{int} = /^((0x)?[0-9]+)$/\1/
2
+ ptype Float{float} = /^([0-9]+\.[0-9]+)$/\1f/
3
+ ptype Bool{int} = True{1} | False{0}
4
+ ptype Unit{int} = Unit{0}
5
+
6
+ type Maybe[a] = Just(a) | Nothing
7
+ type Either[a, b] = Left(a) | Right(b)
8
+ type Tuple2[a, b] = Tuple2(a, b)
9
+ type Tuple3[a, b, c] = Tuple3(a, b, c)
10
+ type Tuple4[a, b, c, d] = Tuple4(a, b, c, d)
11
+ type Tuple5[a, b, c, d, e] = Tuple5(a, b, c, d, e)
12
+
13
+ fst(pair : (a, b)) : a = x where (x, _) = pair
14
+ snd(pair : (a, b)) : b = y where (_, y) = pair
15
+
16
+ foreign - as '-(Int) : Int
17
+ foreign + as '+(Int) : Int
18
+ foreign ! as '!(Bool) : Bool
19
+
20
+ infix || 8
21
+ foreign || as ||(Bool, Bool) : Bool
22
+
23
+ infix && 9
24
+ foreign && as &&(Bool, Bool) : Bool
25
+
26
+ infixl | 10
27
+ foreign | as |(Int, Int) : Int
28
+
29
+ infixl ^ 11
30
+ foreign ^ as ^(Int, Int) : Int
31
+
32
+ infixl & 12
33
+ foreign & as &(Int, Int) : Int
34
+
35
+ infixl == 13
36
+ infixl != 13
37
+ infixl \= 13
38
+ foreign == as ==(Int, Int) : Bool
39
+ foreign != as !=(Int, Int) : Bool
40
+ foreign \= as \=(Int, Int) : Bool
41
+
42
+ infixl < 14
43
+ infixl <= 14
44
+ infixl > 14
45
+ infixl >= 14
46
+ infixl <. 14
47
+ infixl <=. 14
48
+ infixl >. 14
49
+ infixl >=. 14
50
+ foreign < as <(Int, Int) : Bool
51
+ foreign <= as <=(Int, Int) : Bool
52
+ foreign > as >(Int, Int) : Bool
53
+ foreign >= as >=(Int, Int) : Bool
54
+ foreign < as <.(Float, Float) : Bool
55
+ foreign <= as <=.(Float, Float) : Bool
56
+ foreign > as >.(Float, Float) : Bool
57
+ foreign >= as >=.(Float, Float) : Bool
58
+
59
+ infixl << 15
60
+ infixl >> 15
61
+ foreign << as <<(Int, Int) : Int
62
+ foreign >> as >>(Int, Int) : Int
63
+
64
+ infixl + 16
65
+ infixl - 16
66
+ infixl +. 16
67
+ foreign + as +(Int, Int) : Int
68
+ foreign - as -(Int, Int) : Int
69
+ foreign + as +.(Float, Float) : Float
70
+ foreign - as -.(Float, Float) : Float
71
+
72
+ infixl * 17
73
+ infixl / 17
74
+ infixl % 17
75
+ infixl *. 17
76
+ infixl /. 17
77
+ foreign * as *(Int, Int) : Int
78
+ foreign / as /(Int, Int) : Int
79
+ foreign % as %(Int, Int) : Int
80
+ foreign * as *.(Float, Float) : Float
81
+ foreign / as /.(Float, Float) : Float
@@ -0,0 +1,9 @@
1
+ #include <avr/io.h>
2
+ #include "ATMEGA8.h"
3
+
4
+ int portD(int port_num, int high_or_low) {
5
+ high_or_low = (high_or_low == 0 ? 0 : 1);
6
+ DDRD |= 1 << port_num;
7
+ PORTD = (~(1 << port_num) & PORTD) | (high_or_low << port_num);
8
+ return 0;
9
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef IO_AVR_ATMEGA8
2
+ #define IO_AVR_ATMEGA8
3
+
4
+ int portD(int, int);
5
+
6
+ #endif
@@ -0,0 +1,4 @@
1
+ import Base
2
+
3
+ -- PORT-D
4
+ foreign portD as $portD(Int, Bool) : Unit
@@ -0,0 +1,40 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+
4
+ int get_int() {
5
+ int x;
6
+ if (scanf("%d", &x) == EOF) {
7
+ exit(0);
8
+ }
9
+ return x;
10
+ }
11
+
12
+ int put_int(int x) {
13
+ printf("%d\n", x);
14
+ return 0;
15
+ }
16
+
17
+ float get_float() {
18
+ float x;
19
+ if (scanf("%f", &x) == EOF) {
20
+ exit(0);
21
+ }
22
+ return x;
23
+ }
24
+
25
+ int put_float(float x) {
26
+ printf("%f\n", x);
27
+ return 0;
28
+ }
29
+
30
+ int get_int_pair(int* a, int* b) {
31
+ if (scanf("%d %d", a, b) == EOF) {
32
+ exit(0);
33
+ }
34
+ return 0;
35
+ }
36
+
37
+ int put_int_pair(int a, int b) {
38
+ printf("(%d, %d)\n", a, b);
39
+ return 0;
40
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef IO_STDIO_H
2
+ #define IO_STDIO_H
3
+
4
+ int get_int();
5
+ int put_int(int);
6
+
7
+ int get_float();
8
+ int put_float(float);
9
+
10
+ int get_int_pair(int*, int*);
11
+ int put_int_pair(int, int);
12
+
13
+ #endif
@@ -0,0 +1,10 @@
1
+ import Base
2
+
3
+ foreign get_int as $getInt() : Int
4
+ foreign put_int as $putInt(Int) : Unit
5
+
6
+ foreign get_float as $getFloat() : Float
7
+ foreign put_float as $putFloat(Float) : Unit
8
+
9
+ foreign get_int_pair as $getIntPair() : (Int, Int)
10
+ foreign put_int_pair as $putIntPair(Int, Int) : Unit
data/bin/sfrp ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'sfrp'
5
+ Version = SFRP::VERSION
6
+ INCLUDE_PATH = File.expand_path('../../base-library', __FILE__)
7
+ SFRP::Command.from_argv(ARGV, INCLUDE_PATH).run
data/lib/sfrp.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'sfrp/version'
2
+ require 'sfrp/command'
@@ -0,0 +1,73 @@
1
+ require 'sfrp/compiler'
2
+ require 'optparse'
3
+
4
+ module SFRP
5
+ class Command < Struct.new(
6
+ :main_file, :out_dir, :show_files, :include_paths, :error_class, :cc
7
+ )
8
+ def self.from_argv(argv, include_path)
9
+ com = new('Main', './output', false, ['.'], false, nil)
10
+ extract_argv(com, argv)
11
+ com[:include_paths] << include_path
12
+ com
13
+ end
14
+
15
+ def self.extract_argv(com, argv)
16
+ opt_parser = OptionParser.new do |parse|
17
+ desc = 'show paths of the .c file'
18
+ parse.on('--show-files', desc) do
19
+ com.show_files = true
20
+ end
21
+ desc = 'specify output directory (default is ./output)'
22
+ parse.on('--out=DIR_NAME', desc) do |dir|
23
+ com.out_dir = './' + dir.gsub(/\/$/, '')
24
+ end
25
+ desc = 'add include path (multi specification is allowed)'
26
+ parse.on('--include=PATH', desc) do |path|
27
+ com.include_paths << path
28
+ end
29
+ desc = 'only print error (do not generate compiled file)'
30
+ parse.on('--only-print-error', desc) do
31
+ com.out_dir = nil
32
+ end
33
+ desc = 'print error class instead of error message'
34
+ parse.on('--error-class', desc) do
35
+ com.error_class = true
36
+ end
37
+ desc = 'make binary by given command'
38
+ parse.on('--build=CC', desc) do |cc|
39
+ com.cc = cc
40
+ end
41
+ end
42
+ args_without_option = opt_parser.parse(argv)
43
+ case args_without_option.size
44
+ when 0
45
+ nil
46
+ when 1
47
+ com.main_file = args_without_option[0].gsub(/\.sfrp$/, '')
48
+ else
49
+ STDERR.puts 'invalid target specification'
50
+ exit(1)
51
+ end
52
+ rescue OptionParser::InvalidOption => error
53
+ puts error.message
54
+ exit(1)
55
+ end
56
+
57
+ def run
58
+ outs = Compiler.new(main_file, include_paths).compile(out_dir)
59
+ out_paths = outs.map { |o| out_dir + '/' + o + '.c' }
60
+ STDOUT.puts out_paths.join("\n") if show_files
61
+ STDERR.print `#{cc} -o #{main_file} #{out_paths.join(' ')}` if cc
62
+ rescue SFRP::CompileError => cerr
63
+ text = error_class ? cerr.class.to_s : cerr.message
64
+ if out_dir == nil
65
+ STDOUT.puts text
66
+ exit(0)
67
+ else
68
+ STDERR.puts text
69
+ exit(1)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,94 @@
1
+ require 'sfrp/input/set'
2
+ require 'sfrp/raw/set'
3
+ require 'sfrp/flat/set'
4
+ require 'sfrp/poly/set'
5
+ require 'sfrp/mono/set'
6
+ require 'sfrp/low/set'
7
+ require 'sfrp/output/set'
8
+ require 'sfrp/error'
9
+ require 'sfrp/file'
10
+
11
+ module SFRP
12
+ class Compiler
13
+ def initialize(main_fmodule_uri, include_paths)
14
+ @main_fmodule_uri = main_fmodule_uri
15
+ @include_paths = include_paths
16
+ end
17
+
18
+ def make_input_set
19
+ Input::Set.new do |s|
20
+ collect_fmodule_uris(@main_fmodule_uri).each do |uri|
21
+ content = File.read(to_full_path(uri))
22
+ s.append_source_file(uri, content)
23
+ end
24
+ end
25
+ end
26
+
27
+ def make_output_set
28
+ make_input_set
29
+ .to_raw
30
+ .to_flat
31
+ .to_poly
32
+ .to_mono
33
+ .to_low(collect_include_strs(@main_fmodule_uri))
34
+ .to_output
35
+ end
36
+
37
+ def compile(output_dir_path = nil)
38
+ virtual_files = collect_virtual_files(@main_fmodule_uri)
39
+ output_set = make_output_set
40
+ output_set.generate!(output_dir_path, virtual_files) if output_dir_path
41
+ output_file_names
42
+ end
43
+
44
+ def output_file_names
45
+ ['main'] + collect_virtual_files(@main_fmodule_uri).flat_map do |vf|
46
+ vf.file_ext == 'c' ? [vf.fmodule_uri.gsub('.', '/')] : []
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def collect_fmodule_uris(fmodule_uri, visited = {})
53
+ return [] if visited.key?(fmodule_uri)
54
+ visited[fmodule_uri] = true
55
+ content = File.read(to_full_path(fmodule_uri))
56
+ content.each_line.each_with_object([fmodule_uri]) do |line, ary|
57
+ line.match(/import ([A-Z][a-zA-Z0-9]+(\.[A-Z][a-zA-Z0-9]+)*)/) do |m|
58
+ ary.concat(collect_fmodule_uris(m[1], visited))
59
+ end
60
+ end
61
+ end
62
+
63
+ def collect_virtual_files(fmodule_uri)
64
+ collect_fmodule_uris(fmodule_uri).each_with_object([]) do |uri, ary|
65
+ path = to_full_path(uri)
66
+ cpath = path.gsub(/\.sfrp$/, '.c')
67
+ hpath = path.gsub(/\.sfrp$/, '.h')
68
+ if File.exist?(cpath)
69
+ ary << VirtualFile.new(uri, 'c', File.read(cpath))
70
+ end
71
+ if File.exist?(hpath)
72
+ ary << VirtualFile.new(uri, 'h', File.read(hpath))
73
+ end
74
+ end
75
+ end
76
+
77
+ def collect_include_strs(fmodule_uri)
78
+ collect_virtual_files(fmodule_uri).each_with_object([]) do |vf, ary|
79
+ if vf.file_ext == 'h'
80
+ ary << "#{vf.fmodule_uri.gsub('.', '/')}.#{vf.file_ext}"
81
+ end
82
+ end
83
+ end
84
+
85
+ def to_full_path(fmodule_uri)
86
+ relative_path = fmodule_uri.gsub('.', '/')
87
+ @include_paths.each do |path|
88
+ full_path = path + '/' + relative_path + '.sfrp'
89
+ return full_path if File.exist?(full_path)
90
+ end
91
+ raise FileResolveError.new(fmodule_uri, @include_paths)
92
+ end
93
+ end
94
+ end