From 609dbf39d2f66608152ba84d64acd1681826dd17 Mon Sep 17 00:00:00 2001 From: sandyx Date: Fri, 2 Jan 2026 01:39:05 -0600 Subject: [PATCH] first commit --- blocks.rb | 35 ++++++ main.m | 17 +++ objc.rb | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++++ output.txt | 125 ++++++++++++++++++++ parser.rb | 19 ++++ 5 files changed, 525 insertions(+) create mode 100644 blocks.rb create mode 100644 main.m create mode 100755 objc.rb create mode 100644 output.txt create mode 100644 parser.rb diff --git a/blocks.rb b/blocks.rb new file mode 100644 index 0000000..bf57977 --- /dev/null +++ b/blocks.rb @@ -0,0 +1,35 @@ +class PrintyBoy + def initialize(stream) + @stream = stream + end + + def print_em + @stream.each {|y| puts y} + end +end + +class CharStream + include Enumerable + + def initialize(str) + puts "str.chars: #{str.chars.class} of #{str.chars.length} chars" + @str = str.chars + end + + def each(&block) + @str.each &block + end + + def empty? + @str.empty? + end + + def length + @str.length + end +end + +cs = CharStream.new "cockshitbitchcuntaahhhh" +pb = PrintyBoy.new cs + +pb.print_em diff --git a/main.m b/main.m new file mode 100644 index 0000000..271df02 --- /dev/null +++ b/main.m @@ -0,0 +1,17 @@ +@interface NSRuby : NSObject { + int x, y; +} +-(void) sayHello; ++(NSString *) scientificName; +@end + +@implementation +-(void) sayHello { + NSLog(@"Hello, World!"); +} + ++(NSString *) scientificName { + int x = 2 + 5 * 5 / 8; + return @"Homo Sapien!"; +} +@end diff --git a/objc.rb b/objc.rb new file mode 100755 index 0000000..0fc635f --- /dev/null +++ b/objc.rb @@ -0,0 +1,329 @@ +#!/usr/bin/ruby + +def error(msg) + puts "ERROR: #{msg}" + exit 0 +end + +TokenTypes = { + :blackspace => /\S+/, + :whitespace => /\s+/ +} + +BasicTokens = { + :open_brace => /{/, + :closed_brace => /}/, + :open_paren => /\(/, + :closed_paren => /\)/, + :open_bracket => /\[/, + :closed_bracket => /\]/, + :comma => /,/, + :dot => /\./, + :double_quote => /\"/, + :single_quote => /\'/, + :plus => /\+/, + :minus => /\-/, + :mult => /\*/, + :div => /\//, + :number => /[0-9]+/, + :colon => /:/, + :semicolon => /;/, + + :text => /\S/, + :whitespace => /\s+/, + :doubleq => /\"/, +} + +KeywordTokens = { + :intf_decl => /@interface/, + :impl_decl => /@implementation/, + :end => /@end/, + :property => /@property/, + :synthezize => /@synthesize/, +} + +class Token + attr_reader :str + attr_accessor :type + attr_accessor :matcher + + def initialize(str, hash) + @matcher = Matcher.new(hash) + @str, @type = str, @matcher.match(str) + end + + def to_s + "#{@type}: #{@str}" + end + + def combine(token) + @str << token.str + end + + def match_with(hash) + return self unless Token.new(str, hash).matcher.match(@str) + Token.new(str, hash) + end +end + +class Matcher + def initialize(hash) + @hash = hash + end + + def match(val) + @hash.each {|k,v| + return k if val =~ v + } + + return nil + end +end + +class ModeMatcher + def initialize(hash) + @hash = hash + end + + def match(val) + @hash.each {|k,v| + return k if val == v + } + + return nil + end +end + +Modes = { + :intf_decl => :intf_decl, + :impl_decl => :impl_decl, + :end => :end, +} + +class VarDecl + def initialize(type, name) + @type = type + @name = name + end + + def to_s + "#{@type} #{@name};" + end +end + +class VariableDecl + def initialize(stream) + @stream = stream + @modes = [:type, :var, :semicolon] + @mode = :type + end + + def new_from(type, vars) + vars.map { |v| + VarDecl.new(type, v) + } + end + + def parse + vars = [] + + until @stream.empty? + token = @stream.shift + @mode = token.type if token.type == :semicolon + + case @mode + when :type + type = token + @mode = var + when :var + vars << token + when :semicolon + return [VariableDecl.new_from(type, vars), @stream] + end + end + + end +end + +class InterfaceDeclHeader + def initialize(name, superclass) + @name, @superclass = name, superclass + @type = :intf_decl_header + @expect = [:intf_struct_member, :intf_property, :intf_method] + @microexpect = { + :open_brace => :intf_struct_member, + :kw_property => :intf_property, + :minus => :intf_method, + :plus => :class_method, + :end => :any, + } + end + + def self.new_from(par) + first = par.shift + name = par.shift + par.shift + superclass = par.shift + InterfaceDeclHeader.new(name, superclass) + end + + def parse(stream) + token = stream.shift + expected = @microexpect[token] + end +end + +class InterfaceStructMember + def initialize(type, name) + @vartype, @name = vartype, name + @type = :intf_struct_member + @expect = [:intf_struct_member, :intf_property, :intf_method] + end +end + +class InterfaceMethod + def initialize(return_type, name, args) + @return_type, @name, @args = return_type, name, args + @type = :intf_method + @expect [:intf_method, :end] + end +end + +class InterfaceDecl + def initialize(name, superclass) + @name, @superclass = name, superclass + end + + def self.new_from(args) + first = args.shift + puts first if first != "@interface" + name = args.shift + args.shift + superclass = args.shift + InterfaceDecl.new(name, superclass) + end + + def to_s + "@interface #{@name.str} : #{@superclass.str}" + end +end + +class ModeSwitch + def initialize(state) + @state = state + end + + def switch(mode) + @state.mode = mode if @state.modes.include? mode + end +end + +class SyntaxTape + attr_accessor :processed + attr_accessor :remainder + def initialize(processed, remainder) + @processed, @remainder = processed, remainder + end + + def process(parser) + #this should return yet another syntaxtape + parser.parse(@remainder) + end +end + +class StateMachineA + attr_accessor :mode + attr_reader :modes + + def initialize(stream) + @stream = stream + @modes = [:intf_decl, :impl_decl, :end] + @mode = nil + end + + def parse + matcher = ModeSwitch.new(self) + parameters = [] + class_type = nil + until @stream.empty? + token = @stream.shift + matcher.switch(token.type) + + case @mode + when :intf_decl + class_type = InterfaceDeclHeader + parameters << token unless token.type == :whitespace + when :impl_decl + class_type = ImplDeclHeader + parameters << token unless token.type == :whitespace + when :end + parameters << token + return SyntaxTape.new(class_type.new_from(parameters), @stream) + else + puts "unknown state: #{@mode}" + end + end + + end +end + +class Lexer + include Enumerable + + def keywords + [/@interface/] + end + + def initialize(file) + error("expected input file") if file.nil? + @source = File.read(file) + end + + def each(&block) + @source.each_char(&block) + end + + def blackmap + self.map {|c| + Token.new(c, c=~/\s/ ? :whitespace : :blackspace) + } + end + + def matchmap + tokens = self.map {|c| + Token.new(c, BasicTokens) + } + + bleed = 0 + + tokens.filter_map.with_index {|token, idx| + #skips iterations that would result in repeated segments of string + if bleed != 0 + bleed -= 1 + next + end + + next token unless token.type == :text + #combine text into single token + while tokens[idx += 1].type == :text + token.combine(tokens[idx]) + bleed += 1 + next + end + + next token + }.map { |token| + token.match_with(KeywordTokens) + } + end + + def each_token + token = "" + + end +end + +source = Lexer.new(ARGV[0]) +a = StateMachineA.new source.matchmap +tape = a.parse +puts tape.processed diff --git a/output.txt b/output.txt new file mode 100644 index 0000000..3eb5b1c --- /dev/null +++ b/output.txt @@ -0,0 +1,125 @@ +intf_decl: @interface +whitespace: +text: NSRuby +whitespace: +colon: : +whitespace: +text: NSObject +whitespace: +open_brace: { +whitespace: +whitespace: +whitespace: +whitespace: +text: int +whitespace: +text: x +comma: , +whitespace: +text: y +semicolon: ; +whitespace: +closed_brace: } +whitespace: +minus: - +open_paren: ( +text: void +closed_paren: ) +whitespace: +text: sayHello +semicolon: ; +whitespace: +plus: + +open_paren: ( +text: NSString +whitespace: +mult: * +closed_paren: ) +whitespace: +text: scientificName +semicolon: ; +whitespace: +end: @end +whitespace: +whitespace: +impl_decl: @implementation +whitespace: +minus: - +open_paren: ( +text: void +closed_paren: ) +whitespace: +text: sayHello +whitespace: +open_brace: { +whitespace: +whitespace: +whitespace: +whitespace: +text: NSLog +open_paren: ( +text: @ +double_quote: " +text: Hello +comma: , +whitespace: +text: World! +double_quote: " +closed_paren: ) +semicolon: ; +whitespace: +closed_brace: } +whitespace: +whitespace: +plus: + +open_paren: ( +text: NSString +whitespace: +mult: * +closed_paren: ) +whitespace: +text: scientificName +whitespace: +open_brace: { +whitespace: +whitespace: +whitespace: +whitespace: +text: int +whitespace: +text: x +whitespace: +text: = +whitespace: +number: 2 +whitespace: +plus: + +whitespace: +number: 5 +whitespace: +mult: * +whitespace: +number: 5 +whitespace: +div: / +whitespace: +number: 8 +semicolon: ; +whitespace: +whitespace: +whitespace: +whitespace: +text: return +whitespace: +text: @ +double_quote: " +text: Homo +whitespace: +text: Sapien! +double_quote: " +semicolon: ; +whitespace: +closed_brace: } +whitespace: +end: @end +whitespace: diff --git a/parser.rb b/parser.rb new file mode 100644 index 0000000..568713e --- /dev/null +++ b/parser.rb @@ -0,0 +1,19 @@ +class Parser + def initialize(pattern) + @pattern = pattern + end + + def parse(stream) + a = stream.chars + b = a.shift + if b =~ @pattern + return [b, parse(a.join)] + end + end +end + +parser = ->(str) { + parser.call [str[1].flatten.chars.first, str[1].flatten.chars.drop(1)] +} + +p parser.call ["", "Hello, World"]