On 05/11/2016 15:45, Alan Braslau wrote:
Hans, Nicola,

Being a vim user (and not presently taking much advantage of the syntax 
highlighting), and a MP fan, I will take care of this (in coordination with 
Hans, eventually).

Alan

For what is worth, I attach the Ruby script I am using. It outputs the keywords in a format that can be used directly in Vim.

Nicola
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

# Copyright (c) 2016 Lifepillar
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

VERSION = '1.0.0'

def debug title, *info
  return unless $DEBUG
  puts "\033[1;35m[DEBUG]\033[1;39m #{title}\033[0m"
  info.each do |chunk|
    chunk.each_line do |l|
      puts "\033[1;35m[DEBUG]\033[0m #{l.chomp!}"
    end
  end
end

def help; <<-HELP
Usage: parse_metafun [<path> ...]
Options:
    -h, --help                       Show this help message and exit.
        --version                    Print version and exit.
        --debug                      Enable debugging.

Example:
    parse_metafun mp-tool.mp mp-step.mp
  HELP
end

# Parse options
paths = []
n = ARGV.length
i = 0
while i < n
  case ARGV[i]
  when /^--version$/
    puts VERSION
    exit(0)
  when /^--debug$/
    $DEBUG = true
  when /^-h|--help$/
    puts help
    exit(0)
  else # Assume it is a path
    paths << ARGV[i]
  end
  i += 1
end

if paths.empty?
  paths << Dir.entries(".")
end

maxlinelen = 52
defs = {}
saved_vars = {}
known_commands = [
]
known_constants = [
]
known_defs = [
]
known_primary_defs = [
]
known_secondary_defs = [
]
known_tertiary_defs = [
]
known_vardefs = [
]
known_num_exps = [
]
known_types = [
]
false_positives = [
  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', # just to be safe
  'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', # just to be safe
  'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', # just to be safe
]
types = 'boolean|color|cmykcolor|numeric|pair|path|pen|picture|rgbcolor|string|transform'
types += '|' + known_types.join('|')

begin
  paths.each do |p|
    name = File.basename(p)
    defs[name] = {
      'mpCommand' => [],
      'mpDef' => [],
      'mpVardef' => [],
      'mpPrimaryDef' => [],
      'mpSecondaryDef' => [],
      'mpTertiaryDef' => [],
      'mpNewInternal' => [],
      'mpNumExp' => [],
      'mpType' => [],
      'mpVariable' => [],
      'mpConstant' => [],
      'LET' => []
    }
    saved_vars[name] = []
    File.open(p).each_line do |l|
      next if l =~ /^\s*%/ # skip comments
      /^[^%]*\bdef\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          defs[name]['mpDef'] << m[1]
        end
      }
      /^[^%]*\bvardef\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          defs[name]['mpVardef'] << m[1]
        end
      }
      /^[^%]*\bprimarydef\s+\w+\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          defs[name]['mpPrimaryDef'] << m[1]
        end
      }
      /^[^%]*\bsecondarydef\s+\w+\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          defs[name]['mpSecondaryDef'] << m[1]
        end
      }
      /^[^%]*\btertiarydef\s+\w+\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          defs[name]['mpTertiaryDef'] << m[1]
        end
      }
      l.scan(/\bnewinternal\b\s+([^;]+);/).each { |m|
        m[0].split(/,/).each { |w|
          w.strip!
        if w !~ /^_|_$/
            defs[name]['mpNewInternal'] << w
          end
        }
      }
      /^[^%]*\blet\s+(\w+)/.match(l) { |m|
        if m[1] !~ /^_|_$/
          if !false_positives.include?(m[1])
            if known_constants.include?(m[1])
              defs[name]['mpConstant'] << m[1]
            elsif known_types.include?(m[1])
              defs[name]['mpType'] << m[1]
            elsif known_defs.include?(m[1])
              defs[name]['mpDef'] << m[1]
            elsif known_vardefs.include?(m[1])
              defs[name]['mpVardef'] << m[1]
            elsif known_primary_defs.include?(m[1])
              defs[name]['mpPrimaryDef'] << m[1]
            elsif known_secondary_defs.include?(m[1])
              defs[name]['mpSecondaryDef'] << m[1]
            elsif known_tertiary_defs.include?(m[1])
              defs[name]['mpTertiaryDef'] << m[1]
            elsif known_commands.include?(m[1])
              defs[name]['mpCommand'] << m[1]
            elsif known_num_exps.include?(m[1])
              defs[name]['mpNumExp'] << m[1]
            else
              defs[name]['LET'] << m[1]
            end
          end
        end
      }
      l.scan(/\bsave\b\s+([^;]+);/).each do |m| # This considers also save inside comments
        m[0].split(/,/).each do |w|
          saved_vars[name] << w.strip
        end
      end
      l.scan(/\b(#{types})\b\s+([^;]+);/).each { |m|
        m[1].split(/,/).each { |w|
          w.strip!
          w.gsub!(/[\[\]]/, '')
          next unless w =~ /^\w+$/ # Skip if it is not a single token
          next if false_positives.include?(w)
          unless saved_vars.has_key?(name) && saved_vars[name].include?(w)
            if w !~ /^_|_$/
              if known_constants.include?(w)
                defs[name]['mpConstant'] << w
              else
                defs[name]['mpVariable'] << w
              end
            end
          end
        }
      }
    end
  end
  defs.each_key do |n|
    defs[n].each_key do |t|
      defs[n][t].sort!.uniq!
    end
  end
  defs.each_key do |n|
    print "  \" #{n}"
    defs[n].each_pair do |t, l|
      pos = maxlinelen
      l.each do |w|
        if pos + w.length + 1 > maxlinelen
          puts
          print "  syn keyword #{t}"
          print " " * (14 - t.length)
          pos = 0
        end
        print " #{w}"
        pos += w.length + 1
      end
    end
    puts
  end
rescue Interrupt
  puts "parse_metafun interrupted"
  exit(1)
rescue => ex
  puts
  debug 'Backtrace:', ex.backtrace.join("\n")
  "Unexpected exception raised:\n#{ex}"
end

___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the 
Wiki!

maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : http://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : http://contextgarden.net
___________________________________________________________________________________

Reply via email to