sfrp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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