includes DAG cycle finder, and rough drafts of the rest of the depdency graph build
authorThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Fri, 27 Sep 2024 11:09:36 +0000 (11:09 +0000)
committerThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Fri, 27 Sep 2024 11:09:36 +0000 (11:09 +0000)
46 files changed:
build.gradle
developer/#build.gradle# [new file with mode: 0644]
developer/Lethe/buid_from_leaf.gradle [new file with mode: 0644]
developer/Lethe/build.gradle
developer/Lethe/makefile-project.mk
developer/build.gradle
developer/executor/env_build
developer/javac/leaf/ANTLR_OUT_FL.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_Echo.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_Echo_PrintVisitor.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_Echo__Test.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_Swap.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_SwapVisitor.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_SyntaxAnnotate.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_SyntaxAnnotate_PrintVisitor.java [new file with mode: 0644]
developer/javac/leaf/Arithmetic_SyntaxAnnotate__Test.java [new file with mode: 0644]
developer/javac/leaf/RuleNameList.java [new file with mode: 0644]
developer/javac/leaf/RuleNameListRegx.java [new file with mode: 0644]
developer/javac/leaf/StringUtils.java [new file with mode: 0644]
developer/javac/leaf/Synthesize_SyntaxAnnotate.java [new file with mode: 0644]
developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitor.java [new file with mode: 0644]
developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java [new file with mode: 0644]
developer/javac/leaf/TestBench.java [new file with mode: 0644]
developer/javac/primary/ANTLR_OUT_FL.java [deleted file]
developer/javac/primary/Arithmetic_Echo.java [deleted file]
developer/javac/primary/Arithmetic_Echo_PrintVisitor.java [deleted file]
developer/javac/primary/Arithmetic_Echo__Test.java [deleted file]
developer/javac/primary/Arithmetic_Swap.java [deleted file]
developer/javac/primary/Arithmetic_SwapVisitor.java [deleted file]
developer/javac/primary/Arithmetic_SyntaxAnnotate.java [deleted file]
developer/javac/primary/Arithmetic_SyntaxAnnotate_PrintVisitor.java [deleted file]
developer/javac/primary/Arithmetic_SyntaxAnnotate__Test.java [deleted file]
developer/javac/primary/RuleNameList.java [deleted file]
developer/javac/primary/RuleNameListRegx.java [deleted file]
developer/javac/primary/StringUtils.java [deleted file]
developer/javac/primary/Synthesize_SyntaxAnnotate.java [deleted file]
developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitor.java [deleted file]
developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java [deleted file]
developer/javac/primary/TestBench.java [deleted file]
developer/ologist/.ispell_antlr [new file with mode: 0644]
developer/ologist/cycle_dection.html [new file with mode: 0644]
developer/ologist/dependency_graph.html [new file with mode: 0644]
developer/ologist/deps.gradle [new file with mode: 0644]
developer/ologist/emacs.txt
developer/ologist/groovy.el [new file with mode: 0644]
settings.gradle

index ec3a5bb..4312062 100644 (file)
@@ -1,58 +1,94 @@
 
-defaultTasks 'installTools'
+defaultTasks 'installTools', ':developer:preface'
 
-/*--------------------------------------------------------------------------------
-
- Configuration variables
+//--------------------------------------------------------------------------------
+// Project manager should set these configuration variables
+//
+// tool versions
+def antlrVersion = '4.11.1'
+def jdkVersion   = '22.0.1'
+def jdkBuild     = '8'
 
-*/
+// The urls for upstream files
+def antlrUrl = "https://www.antlr.org/download/antlr-${antlrVersion}-complete.jar"
+def jdkUrl = "https://github.com/adoptium/temurin22-binaries/releases/download/jdk-${jdkVersion}%2B${jdkBuild}/OpenJDK22U-jdk_x64_linux_hotspot_${jdkVersion}_${jdkBuild}.tar.gz"
 
+//--------------------------------------------------------------------------------
 // project structure
+//
 def repoHome    = rootDir
 def toolDir     = "${repoHome}/tool"
 def upstreamDir = "${toolDir}/upstream"
 def executorDir = "${toolDir}/executor"
 def erebusDir   = file("${rootDir}/Erebus")
 
-// tool versions
-def antlrVersion = '4.11.1'
-def jdkVersion   = '22.0.1'
-def jdkBuild     = '8'
+//--------------------------------------------------------------------------------
+// Configuration phase code
+//
+// Check that we are in the correct environment
+def repoHomeVar = System.getenv('REPO_HOME')
+def projectVar = System.getenv('PROJECT')
+if(
+  !repoHomeVar 
+  || !projectVar
+){
+  println "REPO_HOME or PROJECT not set, has 'env_pm' or 'env_dev' been sourced?"
+  throw new GradleException("Bailing due to not being able to make sense of the environment.")
+}
+if(
+  projectVar != "GQL_to_Cypher" 
+  && projectVar != "GQL_to_Cypher_PM"
+){
+  println "Expected project 'GQL_to_Cypher', or 'GQL_to_Cypher_PM' but found '${projectVar}'."
+  throw new GradleException("Bailing due to apparently being in the wrong project.")
+}
 
-// The urls for upstream files
-def antlrUrl = "https://www.antlr.org/download/antlr-${antlrVersion}-complete.jar"
-def jdkUrl = "https://github.com/adoptium/temurin22-binaries/releases/download/jdk-${jdkVersion}%2B${jdkBuild}/OpenJDK22U-jdk_x64_linux_hotspot_${jdkVersion}_${jdkBuild}.tar.gz"
+//--------------------------------------------------------------------------------
+// build
+//
+
+task preface {
+  doLast {
+    println "================================================================================"
+    println "installing tools .."
+  }
+}
 
 task installAntlr {
+  dependsOn preface
   doLast {
-    def antlrJar = file("${upstreamDir}/antlr-${antlrVersion}-complete.jar")
-    def antlrExecutorJar = file("${executorDir}/antlr-${antlrVersion}-complete.jar")
+    def antlrJar_FN = "antlr-${antlrVersion}-complete.jar"
+    def antlrJar_FP = file("${upstreamDir}/${antlrJar_FN}")
+    def antlrExecutorJar_FP = file("${executorDir}/${antlrJar_FN}")
 
     mkdir(upstreamDir)
     mkdir(executorDir)
 
-    if (!antlrJar.exists()) {
+    if (!antlrJar_FP.exists()) {
       println "Downloading ANTLR..."
-      new URL(antlrUrl).withInputStream { i -> antlrJar.withOutputStream { it << i } }
+      new URL(antlrUrl).withInputStream { i -> antlrJar_FP.withOutputStream { it << i } }
     }
 
-    if (!antlrExecutorJar.exists()) {
+    if (!antlrExecutorJar_FP.exists()) {
       copy {
-        from antlrJar
+        from antlrJar_FP
         into executorDir
       }
       println "ANTLR installed in executor."
     } else {
       println "ANTLR already installed."
     }
+    project.ext.ANTLRjar = antlrExecutorJar_FP.absolutePath
+
   }
 }
 
 task installJava {
+  dependsOn preface
   doLast {
     def jdkTar = file("${upstreamDir}/jdk-${jdkVersion}.tar.gz")
     def jdkDir = file("${toolDir}/jdk-${jdkVersion}+${jdkBuild}")
-    
+
     mkdir(upstreamDir)
     mkdir(toolDir)
 
@@ -77,7 +113,7 @@ task installJava {
     if (!javaHome.exists()) {
       throw new GradleException("JDK extraction failed.")
     }
-    
+
     // variables saved for use in subproject build scripts
     project.ext.javaHome = jdkDir
 
@@ -90,14 +126,9 @@ task installTools {
   dependsOn installAntlr, installJava
 }
 
-// Ensure all subprojects depend on the tool installation
-subprojects {
-  afterEvaluate { project ->
-    project.tasks.each { task ->
-      task.dependsOn ':installTools'
-    }
-  }
-}
+//--------------------------------------------------------------------------------
+// additional tool install targets
+//
 
 task cleanTool {
   description = 'Cleans the installed tools (but not upstream files)'
@@ -123,7 +154,6 @@ task cleanTool {
 
 task cleanErebus {
   description = "Cleans the project level temporary directory 'Erebus'"  
-  
   doLast {
     if (erebusDir.exists()) {
       erebusDir.eachFile { file ->
diff --git a/developer/#build.gradle# b/developer/#build.gradle#
new file mode 100644 (file)
index 0000000..35450ad
--- /dev/null
@@ -0,0 +1,696 @@
+//---------------------------------------------------------------------------------
+// globals
+
+// string comprehension includes for regular expressions
+def base = "[a-zA-Z0-9_-]+"
+def ext = "[a-zA-Z0-9_-]+$"
+def name = "${base}\\.${ext}"
+def path = ".+/${name}"
+
+//--------------------------------------------------------------------------------
+// Import variables from the environment
+//
+
+def env = [:]
+
+// Required shell environment variables
+def varName_List = [
+  'REPO_HOME',
+  'PROJECT',
+  'ENV_BUILD_VERSION',
+  'DEVELOPER_HOME'
+]
+varName_List.each { varName ->
+  def value = System.getenv(varName) ?: ""
+  env[varName] = value
+}
+
+// Optional shell environment variables
+def varNameOptional_List = [
+  'CLASSPATH'
+]
+varNameOptional_List.each { varName ->
+  def value = System.getenv(varName) ?: ""
+  env[varName] = value
+}
+
+env.CLASSPATH += ":${env.ANTLR_JAR}"
+
+//--------------------------------------------------------------------------------
+// PM installed tools to be used
+//    these should be added to the project object by the installer, and taken
+//    from the project object here.
+//
+// Tools used (set by project manager: JAVA_HOME, ANTLR_JAR, DEVELOPER_HOME)
+def JAVA_COMP_FP = "${env.JAVA_HOME}/bin/javac"   // Java compiler path
+def JAVA_INTERP_FP = "${env.JAVA_HOME}/bin/java"  // Java interpreter path
+def JAVA_ARCHIVE_FP = "${env.JAVA_HOME}/bin/jar"  // Java archive tool path
+
+
+//--------------------------------------------------------------------------------
+// Directory structure
+//
+
+def dir_map = [
+  ,'EXECUTOR_IN'         : 'executor/'
+  ,'ANTLR_IN_LEAF'       : 'ANTLR/'
+  ,'ANTLR_OUT'           : 'javac/ANTLR/'
+  ,'ANTLR_OUT_PARENT'    : 'javac/'
+  ,'JAVA_COMP_IN'        : 'javac/'
+  ,'JAVA_COMP_IN_LEAF': 'javac/leaf/'
+  ,'JAVA_COMP_IN_ANTLR'  : 'javac/ANTLR/'
+  ,'JAVA_COMP_IN_SYN'    : 'javac/synthesized/'
+  ,'JAVA_COMP_OUT'       : 'jvm/'
+  ,'JVM_IN'              : 'jvm/'
+  ,'TEMP'                : 'Erebus/'
+]
+
+// Update CLASSPATH
+env.CLASSPATH += ":${dir_map.JVM_IN}"
+
+// Construct JAVA_COMP_IN_LIST dynamically and add to dp map
+dir_map.JAVA_COMP_IN_LIST = 
+  "${dir_map.JAVA_COMP_IN_LEAF}" +
+  ":${dir_map.JAVA_COMP_IN_ANTLR}" +
+  ":${dir_map.JAVA_COMP_IN_SYN}"
+
+println "CLASSPATH: ${env.CLASSPATH}"
+println "JAVA_COMP_IN_LIST: ${dir_map.JAVA_COMP_IN_LIST}"
+
+
+// Subroutine to print missing environment variables list message
+def printMissingVars(missingVars) {
+  if (missingVars.isEmpty()) {
+    // Print nothing if the list is empty
+    return
+  } else if (missingVars.size() == 1) {
+    println "This environment variable was not set: ${missingVars[0]}"
+  } else {
+    println "These environment variables were not set: ${missingVars.join(', ')}"
+  }
+}
+
+task preface {
+  dependsOn ':installTools'
+  doFirst {
+    
+    // Environment variable checks
+    def error_missing = false
+    def error_project = false
+    def missingVars = [] // To collect missing environment variables
+    varName_List.each { varName ->
+      if (!env[varName]) {
+        error_missing = true
+        missingVars << varName
+      }
+    }
+    printMissingVars(missingVars)
+    if (env.PROJECT != "GQL_to_Cypher") {
+      error_project = true
+      println "Expected project 'GQL_to_Cypher', but found '${env.PROJECT}'."
+    }
+    if (error_missing || error_project) {
+      throw new GradleException("Bailing due to missing environment variables.")
+    }
+  }
+  doLast {
+    println "================================================================================"
+    println "Building project .."
+  }
+}
+
+/*--------------------------------------------------------------------------------
+ Dependency Graph
+
+ A node is a property list.
+
+ A node label is a relative path to a file, or a symbolic value.
+
+ We either a) put nodes in a map that key on the node label then return the node,
+ or b) we use functions that recognize the node label and return a property list.
+ The `lookup(node-label)` function combines all methods to find the node.
+
+ A will formed node will have these properties: label and type.
+
+ A node without a 'neighbor' property is said to be a 'leaf_node'.
+
+ `path` type nodes have a `build` property.  
+*/
+
+//---------------------------------------
+// some helpers
+
+def node_type_set = ['symbol' ,'path'] as Set
+def node_mark_set = ['cycle_member' ,'malformed' ] as Set
+
+/*
+ */
+
+def well_formed_q = { node -> 
+  def form_error_set = [] as Set
+
+  if( 
+    !node.label || node.label.length() == 0 
+  ) 
+    form_error_set << 'no_node_label'
+
+  if( 
+    !node.type || !(node.type in node_type_set) 
+  ) 
+    form_error_set << 'no_node_type'
+
+  if(
+    node.neighbor 
+    && !(node.neighbor instanceof List)
+  )
+    form_error_set << 'neighbor_not_a_list'
+
+  if( 
+    node.type == "path" 
+    && (!node.build || !(node.build instanceof Closure))
+  )
+    form_error_set << 'no_build_code'
+
+  if( 
+    node.type == "symbol" 
+    && node.build
+  )
+    form_error_set << 'symbol_has_build_code'
+
+  if( 
+    node.mark
+    && (node.mark instance of Set)
+    && ! (node.mark.every {it in node_mark_set})
+  ) 
+    form_error_set << 'unregistered_mark'
+
+  return form_error_set
+}
+def is_leaf_q = { node ->  !node.neighbor || node.neighbor.isEmpty() }
+def is_marked_q = { node ->  node.mark && !node.mark.isEmpty() }
+
+
+/*----------------------------------------
+ maps node label -> node
+
+ The keys are the node labels. They are formally added as the value to the
+ `label` property by the lookup function.
+
+ Each leaf node must have a node definition. All path labels that lead to the
+ `javac/leaf` directory are recognized as leaf nodes. A leaf node has a
+ `type` property value of `leaf`, and they can be added to the map at different
+ file paths.
+
+*/
+
+def node_map = [
+
+  "ANTLR_OUT_FL" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/ANTLR_OUT_FL"]
+  ]
+
+  ,"RuleNameList" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/RuleNameList"]
+  ]
+
+  ,"RuleNameListRegx" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/RuleNameListRegx"]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate"
+    ]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate_PrintVisitor" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.JAVA_COMP_IN_LEAF}/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate_PrintVisitor"
+    ]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate_PrintVisitorMethod" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate_PrintVisitorMethod"
+    ]
+  ]
+]
+
+//----------------------------------------
+// the following are recognizer functions that return node definitions.
+
+// any leaf node located in javac/leaf
+def node_leaf_f(node_label) {
+  def leafNodePattern = ~/${dir_map['JAVA_COMP_IN_LEAF']}(.*)/
+  def match = node_label =~ leafNodePattern
+  if (!match) {
+    return [status: "no_match"]
+  }
+  def baseName = match[0][1]
+
+  def leafFilePath = "${dir_map['JAVA_COMP_IN_LEAF']}${baseName}"
+  def leafFile = new File(leafFilePath)
+  if (!leafFile.exists()) {
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node_label
+    ,type: "leaf"
+    ,neighbor: []
+  ]
+}
+
+// any shell wrapper (for wrapping a name corresponding .jar file)
+def node_executor_f(node) {
+
+  def match = node =~ /^(executor\/)(${base})$/
+  if (!match) {
+    return [status: "no_match"]
+  }
+  def baseName = match[0][2]
+
+  def jarFilePath = "${dir_map['JVM_IN']}${baseName}.jar"
+  def wrapperFilePath = "${dir_map['EXECUTOR_IN']}${baseName}"
+
+  def jarFile = new File(jarFilePath)
+  if (!jarFile.exists()) {
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [jarFilePath]
+    ,build: { node, neighbor -> 
+
+      // The script for wrapping the jar file:
+      def wrapper = """
+        #!/usr/bin/env bash
+        ${dir_map['JAVA_INTERP']} -cp \${CLASSPATH}:${dir_map['JVM_IN']}:${dir_map['JVM_IN']}/${baseName}.jar ${baseName} \\\$\\@
+      """
+      
+      new File(wrapperFilePath).withWriter('UTF-8') { writer ->
+        writer.write(wrapper)
+      }
+
+      println "Creating executable wrapper script for ${baseName} in executor directory."
+      "chmod +x ${wrapperFilePath}".execute().text
+    }
+  ]
+}
+
+// any antlr output java file
+def node_grammar_f(node) {
+
+  def match = node =~ /^(${dir_map['ANTLR_OUT']})(${base})(Lexer|Parser|BaseListener|Listener|BaseVisitor|Visitor)\.java$/
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def grammarName = match[0][2]
+  def outputType = match[0][3]
+
+  def grammarFilePath = "${dir_map['ANTLR_IN_LEAF']}${grammarName}.g4"
+  def grammarFile = new File(grammarFilePath)
+
+  if( !grammarFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [grammarFilePath]
+  ]
+}
+
+// any class file (built from a name corresponding .java file)
+def node_class_f(node) {
+
+  def match = node =~ /^(${dir_map['JAVA_COMP_OUT']})(${base})\.class$/
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def baseName = match[0][2]
+  def javaFilePath = "${dir_map['JAVA_COMP_IN_LEAF']}${baseName}.java"
+  def javaFile = new File(javaFilePath)
+
+  if( !javaFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [javaFilePath]
+  ]
+}
+
+// any jar file (built from a corresponding class file)
+def node_jar_f(node) {
+
+  // Use the symbolic name and base patterns
+  def match = node =~ /^(${dir_map['JAVA_COMP_OUT']})(${base})\.jar$/
+
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def baseName = match[0][2]
+  def classFilePath = "${dir_map['JAVA_COMP_OUT']}${baseName}.class"
+  def classFile = new File(classFilePath)
+
+  if( !classFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [classFilePath]
+    ,build: { node, neighbor ->
+      println "Building jar for ${baseName}"
+      def command = "${ext.javaHome}/bin/jar cf ${baseName}.jar -C ${dir_map['JAVA_COMP_OUT']} ${baseName}.class"
+      return command.execute().text;
+    }
+  ]
+}
+
+// list of the recognizer functions
+def node_f_list = [
+  node_leaf_f
+  ,node)executor_f
+  ,node_grammar_f
+  ,node_class_f
+  ,node_jar_f
+]
+
+
+// combines the map and recognizer functions into a single lookup
+def lookup(node_label, verbose = false){
+  // the actual lookup
+  def lookup_node = node_map[node_label]
+  if( lookup_node ){
+    lookup_node.label = node_label
+  } else {
+    def match_result
+    for( func in node_f_list ){
+      match_result = func(node_label)
+      if( match_result.status == "matched" ){
+        lookup_node = match_result
+        break
+      }
+    }
+  }
+
+  if( !lookup_node ){
+    if( verbose ) println "Lookup error: Node ${node_label} could not be found."
+    return null
+  }
+
+  // If we already marked this one as malformed, do not check it again
+  // This is done primarily to avoid duplicate error messages, as it isn't a big
+  // performance win.
+  if( lookup_node.mark && ('malformed' in lookup_node.mark) ) return null
+
+  // Check if the node is well formed
+  def form_errors = well_formed_q(lookup_node)
+  if( !form_errors.isEmpty() ){
+    // Mark the node as malformed
+    if( !lookup_node.mark ) lookup_node.mark = [] as Set
+    lookup_node.mark << 'malformed' 
+
+    // Tell the user
+    if( verbose ){
+      println "Lookup error: Node ${node_label} is malformed due to: ${form_errors.join(', ')}"
+    }
+
+    // Refuse to return a malformed node
+    return null
+  }
+
+  return lookup_node
+}
+
+/*--------------------------------------------------------------------------------
+ is_acyclic_q checks a dependency graph for cycles
+
+ given a dependency graph. Returns either 'given_argument_not_accepted',
+ `cycles` or `acyclic`.
+
+ marks the nodes that are in cycles.
+
+ There is a call function and a helper function
+
+*/
+
+def is_acyclic_q_descend(path_stack ,boolean verbose = true){
+  def local_path = path_stack.collect{ node_label -> lookup(node_label) }
+  def local_node = local_path[-1]
+  def cycle_start_index
+
+  do{
+    // Check for a cycle in the local path
+    cycle_start_index = local_path[0..-2].findIndexOf{ node -> node.label == local_node.label }
+    if( cycle_start_index != -1 ){ // Cycle detected
+      if( verbose ) print "is_acyclic_q:: dependency cycle found:"
+      local_path[cycle_start_index..-1].each{ cycle_node ->
+        if( verbose ) print " ${cycle_node.label}"
+        cycle_node.mark = cycle_node.mark ?: [] as Set // Initialize mark set if needed
+        cycle_node.mark << 'cycle_member'
+      }
+      if( verbose ) println ""
+      // Pop off the stack above the cycle start, so that search can continue if desired
+      path_stack = path_stack[0..cycle_start_index]
+      return 'cycle_found'
+    }
+
+    // Put this test after the cycle detector in case another definition with
+    // the same label had children and participated in a cycle.
+    if( local_node.neighbor.isEmpty() ) return 'leaf_node'
+
+    // Descend further into the tree.
+    path_stack << local_node.neighbor.clone()
+    local_node = lookup(local_node.neighbor[0])
+    local_path << local_node
+  }while( true )
+}
+
+def is_acyclic_q(root_node_labels ,boolean verbose = true){
+  // We are optimistic.
+  def return_value = 'acyclic'
+
+  // Initialize the DFS tree iterator.
+  def path_stack = []
+  path_stack << root_node_labels.clone()
+
+  // iterate over left side tree descent, not ideal as it starts at the
+  // root each time, but avoids complexity in the cycle detection logic.
+  do{
+    def result = is_acyclic_q_descend(path_stack ,verbose)
+    if(result == 'cycle_found') return_value = result
+
+    // increment the iterator to the next leftmost path
+    def top_list = path_stack[-1]
+    top_list.remove(0)
+    if( top_list.isEmpty() ) path_stack.pop()
+
+  }while( !path_stack.isEmpty() )
+
+  return return_value
+}
+
+// LocalWords:  FN FPL DN DNL RuleNameListRegx RuleNameList PrintVisitorMethod
+// LocalWords:  PrintVisitor SyntaxAnnotate
+
+/*--------------------------------------------------------------------------------
+ run the build scripts
+   depends upon is_acyclic having already marked up the graph.
+
+Initialization:
+* visited: A set to keep track of visited nodes.
+* build_order: A list to store the nodes in the order they should be built.
+
+Depth-First Search (DFS):
+* The dfs function performs a depth-first traversal of the graph.
+* It looks up the node using the lookup function.
+* If the node has already been visited, it returns.
+* Otherwise, it marks the node as visited and recursively visits its neighbors.
+* After visiting all neighbors, it adds the node to the build_order list.
+
+Build Script Execution:
+* After the DFS traversal, the build_order list is reversed to ensure that leaf nodes are built first.
+*  The build scripts for each node are executed in the correct order.
+
+-- add date checks
+
+*/
+
+def run_build_scripts(root_node_labels ,boolean verbose = false){
+  def visited = [] as Set
+  def build_order = []
+
+  def dfs(node_label){
+    def node = lookup(node_label ,verbose)
+    if( !node ) return
+
+    if( node.label in visited ) return
+    visited << node.label
+
+    node.neighbor.each{ neighbor_label ->
+      dfs(neighbor_label)
+    }
+
+    build_order << node
+  }
+
+  root_node_labels.each{ root_label ->
+    dfs(root_label)
+  }
+
+  build_order.reverse().each{ node ->
+    if( node.build ){
+      println "Running build script for ${node.label}"
+      node.build(node ,node.neighbor)
+    }
+  }
+}
+
+// Example usage
+def root_node_labels = ["ANTLR_OUT_FL" ,"RuleNameList"]
+run_build_scripts(root_node_labels ,true)
+
+
+def run_build_scripts(root_node_labels ,boolean verbose = false){
+  if( root_node_labels.isEmpty() ) return
+
+  def visited = [] as Set
+  def build_order = []
+  def stack = []
+
+  root_node_labels.each{ root_label ->
+    stack << root_label
+  }
+
+  do{
+    def node_label = stack.pop()
+    def node = lookup(node_label ,verbose)
+    if( !node ) continue
+
+    if( node.label in visited ) continue
+    visited << node.label
+
+    node.neighbor.each{ neighbor_label ->
+      stack << neighbor_label
+    }
+
+    build_order << node
+  }while( !stack.isEmpty() )
+
+  build_order.reverse().each{ node ->
+    if( node.build ){
+      println "Running build script for ${node.label}"
+      node.build(node ,node.neighbor)
+    }
+  }
+}
+
+--------------------
+
+def should_build(node, verbose = false){
+  if( node.mark && ('malformed' in node.mark || 'cycle_member' in node.mark) ){
+    if( verbose ) println "Skipping build for ${node.label} due to errors or cycle membership."
+    return false
+  }
+
+  def nodeFile = new File(node.label)
+  if( !nodeFile.exists() ){
+    if( verbose ) println "Node file ${node.label} does not exist."
+    return false
+  }
+
+  def nodeLastModified = nodeFile.lastModified()
+  def shouldBuild = false
+
+  node.neighbor.each{ neighbor_label ->
+    def neighborNode = lookup(neighbor_label, verbose)
+    if( !neighborNode || neighborNode.type != 'path' ){
+      if( verbose ) println "Dependency ${neighbor_label} is missing or not a path type."
+      return false
+    }
+
+    def neighborFile = new File(neighbor_label)
+    if( !neighborFile.exists() ){
+      if( verbose ) println "Dependency file ${neighbor_label} does not exist."
+      return false
+    }
+
+    def neighborLastModified = neighborFile.lastModified()
+    if( neighborLastModified > nodeLastModified ){
+      shouldBuild = true
+    }
+  }
+
+  return shouldBuild
+}
+
+def run_build_scripts(root_node_labels ,boolean verbose = false){
+  if( root_node_labels.isEmpty() ) return
+
+  def visited = [] as Set
+  def build_order = []
+  def stack = []
+
+  root_node_labels.each{ root_label ->
+    stack << root_label
+  }
+
+  do{
+    def node_label = stack.pop()
+    def node = lookup(node_label ,verbose)
+    if( !node ) continue
+
+    if( node.label in visited ) continue
+    visited << node.label
+
+    node.neighbor.each{ neighbor_label ->
+      stack << neighbor_label
+    }
+
+    build_order << node
+  }while( !stack.isEmpty() )
+
+  build_order.reverse().each{ node ->
+    if( node.build && should_build(node ,verbose) ){
+      println "Running build script for ${node.label}"
+      node.build(node ,node.neighbor)
+    }
+  }
+}
+
+// Example usage
+def root_node_labels = ["ANTLR_OUT_FL" ,"RuleNameList"]
+run_build_scripts(root_node_labels ,true)
+
+
+
+// Example usage
+def root_node_labels = ["ANTLR_OUT_FL" ,"RuleNameList"]
+run_build_scripts(root_node_labels ,true)
diff --git a/developer/Lethe/buid_from_leaf.gradle b/developer/Lethe/buid_from_leaf.gradle
new file mode 100644 (file)
index 0000000..c23a159
--- /dev/null
@@ -0,0 +1,68 @@
+/*--------------------------------------------------------------------------------
+ build_from_leaf
+
+ Accepts `build_result_fpl` and `leaf_dependency_fpl` (fpl = file path list). 
+ Typically, `build_result_fpl` will hold a single item, representing the target 
+ to be built, and `leaf_dependency_fpl` contains the leaf dependencies for that 
+ target.
+
+ This function checks the build status of the target relative to its dependencies.
+
+ It returns a dictionary with the following fields based on the result of the check:
+
+     type   -> A string indicating the result type:
+               'no_build_target_specified', 'non_existent_build_target',
+               'up_to_date', or 'need_to_build'.
+
+     message -> A string message describing the result (optional).
+
+     missing -> If type is 'non_existent_build_target', this field contains the 
+                list of missing build targets.
+
+     build_result -> If type is 'need_to_build', this field contains the list 
+                     of build result filenames that need to be rebuilt.
+*/
+
+def build_from_leaf(build_result_fpl ,leaf_dependency_fpl) {
+
+  if( !build_result_fpl || build_result_fpl.isEmpty() ){
+    return [
+      type: "no_build_target_specified"
+      ,message: "No build target specified"
+    ]
+  }
+
+  // Check if any build result file does not exist
+  def missing_build_fpl = build_result_fpl.findAll{ file_path ->
+    !new File(file_path).exists()
+  }
+  
+  if( !missing_build_fpl.isEmpty() ){
+    return [
+      type: "non_existent_build_target"
+      ,message: "Missing build targets"
+      ,missing: missing_build_fpl
+    ]
+  }
+
+  // Check if any dependency is newer than the build result files
+  def all_up_to_date_bool = build_result_fpl.every{ result_file_path ->
+    def result_file = new File(result_file_path)
+    !leaf_dependency_fpl.any{ dep_path ->
+      new File(dep_path).lastModified() > result_file.lastModified()
+    }
+  }
+
+  if( all_up_to_date_bool ){
+    return [
+      type: "up_to_date"
+      ,message: "Build result is up to date"
+    ]
+  }else{
+    return [
+      type: "need_to_build"
+      ,message: "Build result needs to be rebuilt"
+      ,build_result: build_result_fpl
+    ]
+  }
+}
index b5ab4a6..e53add0 100644 (file)
@@ -1,8 +1,23 @@
 task setup {
   doLast {
-    def dirs = ["$(ANTLR_IN_PRIMARY_DIR)", "$(JAVA_COMP_IN_PRIMARY_DIR)", "$(JVM_IN_DIR)", "$(EXECUTOR_IN_DIR)", "test", "deprecated", "experiment", "ologist", "temporary"]
+    def dirs = [
+      "$(ANTLR_IN_PRIMARY_DIR)"
+      ,"$(JAVA_COMP_IN_DIR)"
+      ,"$(JAVA_COMP_IN_PRIMARY_DIR)"
+      ,"$(JAVA_COMP_IN_ANTLR_DIR)"
+      ,"$(JAVA_COMP_IN_SYN_DIR)"
+      ,"$(JVM_IN_DIR)"
+      ,"$(EXECUTOR_IN_DIR)"
+      ,"test"
+      ,"deprecated"
+      ,"experiment"
+      ,"ologist"
+      ,"temporary"
+    ]
     dirs.each { dir ->
-      mkdir dir
+      if (!file(dir).exists()) {
+        mkdir dir
+      }
     }
   }
 }
@@ -54,38 +69,3 @@ tasks.withType(Exec) {
     println "Executing $name"
   }
 }
-
-
-----------------------
-// Function to compile .java files to .class files
-def compileJava(source, target) {
-  tasks.create(name: "compile${source}", type: Exec) {
-    commandLine '$(JAVA_COMP)', '-d', '$(JAVA_COMP_OUT_DIR)', '-sourcepath', '$(JAVA_COMP_IN_DL)', source
-    doLast {
-      println "Compiled ${source} to ${target}"
-    }
-  }
-}
-
-// Function to create .jar files from .class files
-def createJar(source, target) {
-  tasks.create(name: "jar${source}", type: Exec) {
-    commandLine '$(JAVA_ARCHIVE)', 'cf', target, '-C', '$(JAVA_COMP_OUT_DIR)', source
-    doLast {
-      println "Created ${target}"
-    }
-  }
-}
-
-// Function to create wrapper scripts from .jar files
-def createWrapper(source, target) {
-  tasks.create(name: "wrapper${source}", type: Exec) {
-    doLast {
-      def script = new File(target)
-      script.text = "#!/usr/bin/env bash\n$(JAVA_INTERP) -cp ${CLASSPATH}:${JVM_IN_DP}:${JVM_IN_DP}/${source}.jar ${source} \$@"
-      script.setExecutable(true)
-      println "Created program ${target}"
-    }
-  }
-}
-  
index ea8a0f3..7f8d6ef 100644 (file)
@@ -46,7 +46,7 @@ Synthesize_SyntaxAnnotate_PrintVisitor:\
   $(EXECUTOR_IN_DIR)/Synthesize_SyntaxAnnotate_PrintVisitor
 
 Synthesize_SyntaxAnnotate:\
-  $(JAVA_COMP_IN_PRIMARY_DIR)/StringUtils.java\
+  $(JAVA_COMP_IN_PRIMARY_DIR)/StringUtils.java\https://github.com/Thomas-Walker-Lynch/GQL_to_Cypher
   $(EXECUTOR_IN_DIR)/Synthesize_SyntaxAnnotate
 
 #-----------------------------------------------
@@ -236,6 +236,7 @@ $(JAVA_COMP_OUT_DIR)/%.class: $(JAVA_COMP_IN_PRIMARY_DIR)/%.java
 .PRECIOUS: $(JAVA_COMP_OUT_DIR)/%.jar
 
 # make .jar from .class file
+$(JAVA_COMP_OUT_DIR)/%.class: $(JAVA_COMP_IN_PRIMARY_DIR)/%.java
 $(JAVA_COMP_OUT_DIR)/%.jar: $(JAVA_COMP_OUT_DIR)/%.class
        @echo "Building $*..."
        $(JAVA_ARCHIVE) cf $@ -C $(JAVA_COMP_OUT_DIR) $*.class
index e53add0..ffc383d 100644 (file)
-task setup {
-  doLast {
-    def dirs = [
-      "$(ANTLR_IN_PRIMARY_DIR)"
-      ,"$(JAVA_COMP_IN_DIR)"
-      ,"$(JAVA_COMP_IN_PRIMARY_DIR)"
-      ,"$(JAVA_COMP_IN_ANTLR_DIR)"
-      ,"$(JAVA_COMP_IN_SYN_DIR)"
-      ,"$(JVM_IN_DIR)"
-      ,"$(EXECUTOR_IN_DIR)"
-      ,"test"
-      ,"deprecated"
-      ,"experiment"
-      ,"ologist"
-      ,"temporary"
-    ]
-    dirs.each { dir ->
-      if (!file(dir).exists()) {
-        mkdir dir
+//---------------------------------------------------------------------------------
+// globals
+
+// string comprehension includes for regular expressions
+def base = "[a-zA-Z0-9_-]+"
+def ext = "[a-zA-Z0-9_-]+$"
+def name = "${base}\\.${ext}"
+def path = ".+/${name}"
+
+//--------------------------------------------------------------------------------
+// Import variables from the environment
+//
+
+def env = [:]
+
+// Required shell environment variables
+def varName_List = [
+  'REPO_HOME',
+  'PROJECT',
+  'ENV_BUILD_VERSION',
+  'DEVELOPER_HOME'
+]
+varName_List.each { varName ->
+  def value = System.getenv(varName) ?: ""
+  env[varName] = value
+}
+
+// Optional shell environment variables
+def varNameOptional_List = [
+  'CLASSPATH'
+]
+varNameOptional_List.each { varName ->
+  def value = System.getenv(varName) ?: ""
+  env[varName] = value
+}
+
+env.CLASSPATH += ":${env.ANTLR_JAR}"
+
+//--------------------------------------------------------------------------------
+// PM installed tools to be used
+//    these should be added to the project object by the installer, and taken
+//    from the project object here.
+//
+// Tools used (set by project manager: JAVA_HOME, ANTLR_JAR, DEVELOPER_HOME)
+def JAVA_COMP_FP = "${env.JAVA_HOME}/bin/javac"   // Java compiler path
+def JAVA_INTERP_FP = "${env.JAVA_HOME}/bin/java"  // Java interpreter path
+def JAVA_ARCHIVE_FP = "${env.JAVA_HOME}/bin/jar"  // Java archive tool path
+
+
+//--------------------------------------------------------------------------------
+// Directory structure
+//
+
+def dir_map = [
+  ,'EXECUTOR_IN'         : 'executor/'
+  ,'ANTLR_IN_LEAF'       : 'ANTLR/'
+  ,'ANTLR_OUT'           : 'javac/ANTLR/'
+  ,'ANTLR_OUT_PARENT'    : 'javac/'
+  ,'JAVA_COMP_IN'        : 'javac/'
+  ,'JAVA_COMP_IN_LEAF': 'javac/leaf/'
+  ,'JAVA_COMP_IN_ANTLR'  : 'javac/ANTLR/'
+  ,'JAVA_COMP_IN_SYN'    : 'javac/synthesized/'
+  ,'JAVA_COMP_OUT'       : 'jvm/'
+  ,'JVM_IN'              : 'jvm/'
+  ,'TEMP'                : 'Erebus/'
+]
+
+// Update CLASSPATH
+env.CLASSPATH += ":${dir_map.JVM_IN}"
+
+// Construct JAVA_COMP_IN_LIST dynamically and add to dp map
+dir_map.JAVA_COMP_IN_LIST = 
+  "${dir_map.JAVA_COMP_IN_LEAF}" +
+  ":${dir_map.JAVA_COMP_IN_ANTLR}" +
+  ":${dir_map.JAVA_COMP_IN_SYN}"
+
+println "CLASSPATH: ${env.CLASSPATH}"
+println "JAVA_COMP_IN_LIST: ${dir_map.JAVA_COMP_IN_LIST}"
+
+
+// Subroutine to print missing environment variables list message
+def printMissingVars(missingVars) {
+  if (missingVars.isEmpty()) {
+    // Print nothing if the list is empty
+    return
+  } else if (missingVars.size() == 1) {
+    println "This environment variable was not set: ${missingVars[0]}"
+  } else {
+    println "These environment variables were not set: ${missingVars.join(', ')}"
+  }
+}
+
+task preface {
+  dependsOn ':installTools'
+  doFirst {
+    
+    // Environment variable checks
+    def error_missing = false
+    def error_project = false
+    def missingVars = [] // To collect missing environment variables
+    varName_List.each { varName ->
+      if (!env[varName]) {
+        error_missing = true
+        missingVars << varName
       }
     }
+    printMissingVars(missingVars)
+    if (env.PROJECT != "GQL_to_Cypher") {
+      error_project = true
+      println "Expected project 'GQL_to_Cypher', but found '${env.PROJECT}'."
+    }
+    if (error_missing || error_project) {
+      throw new GradleException("Bailing due to missing environment variables.")
+    }
+  }
+  doLast {
+    println "================================================================================"
+    println "Building project .."
   }
 }
 
-task tool(type: Exec) {
-  dependsOn setup
-  commandLine '$(BIN_MAKE)', '-f', '$(EXECUTOR_IN_DIR)/makefile-tool.mk', '-$(MAKEFLAGS)', 'all'
+/*--------------------------------------------------------------------------------
+ Dependency Graph
+
+ A node is a property list.
+
+ A node label is a relative path to a file, or a symbolic value.
+
+ We either a) put nodes in a map that key on the node label then return the node,
+ or b) we use functions that recognize the node label and return a property list.
+ The `lookup(node-label)` function combines all methods to find the node.
+
+ A will formed node will have these properties: label and type.
+
+ A node without a 'neighbor' property is said to be a 'leaf_node'.
+
+ `path` type nodes have a `build` property.  
+*/
+
+//---------------------------------------
+// some helpers
+
+def node_type_set = ['symbol' ,'path'] as Set
+def node_mark_set = ['cycle_member' ,'malformed' ] as Set
+
+/*
+ */
+
+def well_formed_q = { node -> 
+  def form_error_set = [] as Set
+
+  if( 
+    !node.label || node.label.length() == 0 
+  ) 
+    form_error_set << 'no_node_label'
+
+  if( 
+    !node.type || !(node.type in node_type_set) 
+  ) 
+    form_error_set << 'no_node_type'
+
+  if(
+    node.neighbor 
+    && !(node.neighbor instanceof List)
+  )
+    form_error_set << 'neighbor_not_a_list'
+
+  if( 
+    node.type == "path" 
+    && (!node.build || !(node.build instanceof Closure))
+  )
+    form_error_set << 'no_build_code'
+
+  if( 
+    node.type == "symbol" 
+    && node.build
+  )
+    form_error_set << 'symbol_has_build_code'
+
+  if( 
+    node.mark
+    && (node.mark instance of Set)
+    && ! (node.mark.every {it in node_mark_set})
+  ) 
+    form_error_set << 'unregistered_mark'
+
+  return form_error_set
 }
+def is_leaf_q = { node ->  !node.neighbor || node.neighbor.isEmpty() }
+def is_marked_q = { node ->  node.mark && !node.mark.isEmpty() }
+
+
+/*----------------------------------------
+ maps node label -> node
+
+ The keys are the node labels. They are formally added as the value to the
+ `label` property by the lookup function.
+
+ Each leaf node must have a node definition. All path labels that lead to the
+ `javac/leaf` directory are recognized as leaf nodes. A leaf node has a
+ `type` property value of `leaf`, and they can be added to the map at different
+ file paths.
+
+*/
+
+def node_map = [
+
+  "ANTLR_OUT_FL" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/ANTLR_OUT_FL"]
+  ]
+
+  ,"RuleNameList" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/RuleNameList"]
+  ]
+
+  ,"RuleNameListRegx" : [
+    ,type: "symbol"
+    ,neighbor: ["${dir_map.EXECUTOR_IN}/RuleNameListRegx"]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate"
+    ]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate_PrintVisitor" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.JAVA_COMP_IN_LEAF}/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate_PrintVisitor"
+    ]
+  ]
+
+  ,"Synthesize_SyntaxAnnotate_PrintVisitorMethod" : [
+    ,type: "symbol"
+    ,neighbor: [
+      "${dir_map.JAVA_COMP_IN_LEAF}/StringUtils.java"
+      ,"${dir_map.EXECUTOR_IN}/Synthesize_SyntaxAnnotate_PrintVisitorMethod"
+    ]
+  ]
+]
+
+//----------------------------------------
+// the following are recognizer functions that return node definitions.
+
+// any leaf node located in javac/leaf
+def node_leaf_f(node_label) {
+  def leafNodePattern = ~/${dir_map['JAVA_COMP_IN_LEAF']}(.*)/
+  def match = node_label =~ leafNodePattern
+  if (!match) {
+    return [status: "no_match"]
+  }
+  def baseName = match[0][1]
+
+  def leafFilePath = "${dir_map['JAVA_COMP_IN_LEAF']}${baseName}"
+  def leafFile = new File(leafFilePath)
+  if (!leafFile.exists()) {
+    return [status: "no_match"]
+  }
 
-task project(type: Exec) {
-  dependsOn tool
-  commandLine '$(BIN_MAKE)', '-f', '$(EXECUTOR_IN_DIR)/makefile-project.mk', '-$(MAKEFLAGS)', 'all'
+  return [
+    status: "matched"
+    ,label: node_label
+    ,type: "leaf"
+    ,neighbor: []
+  ]
 }
 
-task clean {
-  doLast {
-    println "Use the command `clean <option>` instead of make."
+// any shell wrapper (for wrapping a name corresponding .jar file)
+def node_executor_f(node) {
+
+  def match = node =~ /^(executor\/)(${base})$/
+  if (!match) {
+    return [status: "no_match"]
   }
+  def baseName = match[0][2]
+
+  def jarFilePath = "${dir_map['JVM_IN']}${baseName}.jar"
+  def wrapperFilePath = "${dir_map['EXECUTOR_IN']}${baseName}"
+
+  def jarFile = new File(jarFilePath)
+  if (!jarFile.exists()) {
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [jarFilePath]
+    ,build: { node, neighbor -> 
+
+      // The script for wrapping the jar file:
+      def wrapper = """
+        #!/usr/bin/env bash
+        ${dir_map['JAVA_INTERP']} -cp \${CLASSPATH}:${dir_map['JVM_IN']}:${dir_map['JVM_IN']}/${baseName}.jar ${baseName} \\\$\\@
+      """
+      
+      new File(wrapperFilePath).withWriter('UTF-8') { writer ->
+        writer.write(wrapper)
+      }
+
+      println "Creating executable wrapper script for ${baseName} in executor directory."
+      "chmod +x ${wrapperFilePath}".execute().text
+    }
+  ]
 }
 
-task version {
-  doLast {
-    println "ANTLR_JAR is '${notdir(ANTLR_JAR)}'"
-    exec {
-      commandLine '$(JAVA_COMP)', '--version'
+// any antlr output java file
+def node_grammar_f(node) {
+
+  def match = node =~ /^(${dir_map['ANTLR_OUT']})(${base})(Lexer|Parser|BaseListener|Listener|BaseVisitor|Visitor)\.java$/
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def grammarName = match[0][2]
+  def outputType = match[0][3]
+
+  def grammarFilePath = "${dir_map['ANTLR_IN_LEAF']}${grammarName}.g4"
+  def grammarFile = new File(grammarFilePath)
+
+  if( !grammarFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [grammarFilePath]
+  ]
+}
+
+// any class file (built from a name corresponding .java file)
+def node_class_f(node) {
+
+  def match = node =~ /^(${dir_map['JAVA_COMP_OUT']})(${base})\.class$/
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def baseName = match[0][2]
+  def javaFilePath = "${dir_map['JAVA_COMP_IN_LEAF']}${baseName}.java"
+  def javaFile = new File(javaFilePath)
+
+  if( !javaFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [javaFilePath]
+  ]
+}
+
+// any jar file (built from a corresponding class file)
+def node_jar_f(node) {
+
+  // Use the symbolic name and base patterns
+  def match = node =~ /^(${dir_map['JAVA_COMP_OUT']})(${base})\.jar$/
+
+  if( !match ){
+    return [status: "no_match"]
+  }
+
+  def baseName = match[0][2]
+  def classFilePath = "${dir_map['JAVA_COMP_OUT']}${baseName}.class"
+  def classFile = new File(classFilePath)
+
+  if( !classFile.exists() ){
+    return [status: "no_match"]
+  }
+
+  return [
+    status: "matched"
+    ,label: node
+    ,type: "path"
+    ,neighbor: [classFilePath]
+    ,build: { node, neighbor ->
+      println "Building jar for ${baseName}"
+      def command = "${ext.javaHome}/bin/jar cf ${baseName}.jar -C ${dir_map['JAVA_COMP_OUT']} ${baseName}.class"
+      return command.execute().text;
     }
-    exec {
-      commandLine '$(JAVA_ARCHIVE)', '--version'
+  ]
+}
+
+// list of the recognizer functions
+def node_f_list = [
+  node_leaf_f
+  ,node)executor_f
+  ,node_grammar_f
+  ,node_class_f
+  ,node_jar_f
+]
+
+
+// combines the map and recognizer functions into a single lookup
+def lookup(node_label, verbose = false){
+  // the actual lookup
+  def lookup_node = node_map[node_label]
+  if( lookup_node ){
+    lookup_node.label = node_label
+  } else {
+    def match_result
+    for( func in node_f_list ){
+      match_result = func(node_label)
+      if( match_result.status == "matched" ){
+        lookup_node = match_result
+        break
+      }
     }
-    exec {
-      commandLine 'make', '-v'
+  }
+
+  if( !lookup_node ){
+    if( verbose ) println "Lookup error: Node ${node_label} could not be found."
+    return null
+  }
+
+  // If we already marked this one as malformed, do not check it again
+  // This is done primarily to avoid duplicate error messages, as it isn't a big
+  // performance win.
+  if( lookup_node.mark && ('malformed' in lookup_node.mark) ) return null
+
+  // Check if the node is well formed
+  def form_errors = well_formed_q(lookup_node)
+  if( !form_errors.isEmpty() ){
+    // Mark the node as malformed
+    if( !lookup_node.mark ) lookup_node.mark = [] as Set
+    lookup_node.mark << 'malformed' 
+
+    // Tell the user
+    if( verbose ){
+      println "Lookup error: Node ${node_label} is malformed due to: ${form_errors.join(', ')}"
     }
-    println "makefile 0.4"
+
+    // Refuse to return a malformed node
+    return null
   }
+
+  return lookup_node
+}
+
+/*--------------------------------------------------------------------------------
+ is_acyclic_q checks a dependency graph for cycles
+
+ given a dependency graph. Returns either 'given_argument_not_accepted',
+ `cycles` or `acyclic`.
+
+ marks the nodes that are in cycles.
+
+ There is a call function and a helper function
+
+*/
+
+def is_acyclic_q_descend(path_stack ,boolean verbose = true){
+  def local_path = path_stack.collect{ node_label -> lookup(node_label) }
+  def local_node = local_path[-1]
+  def cycle_start_index
+
+  do{
+    // Check for a cycle in the local path
+    cycle_start_index = local_path[0..-2].findIndexOf{ node -> node.label == local_node.label }
+    if( cycle_start_index != -1 ){ // Cycle detected
+      if( verbose ) print "is_acyclic_q:: dependency cycle found:"
+      local_path[cycle_start_index..-1].each{ cycle_node ->
+        if( verbose ) print " ${cycle_node.label}"
+        cycle_node.mark = cycle_node.mark ?: [] as Set // Initialize mark set if needed
+        cycle_node.mark << 'cycle_member'
+      }
+      if( verbose ) println ""
+      // Pop off the stack above the cycle start, so that search can continue if desired
+      path_stack = path_stack[0..cycle_start_index]
+      return 'cycle_found'
+    }
+
+    // Put this test after the cycle detector in case another definition with
+    // the same label had children and participated in a cycle.
+    if( local_node.neighbor.isEmpty() ) return 'leaf_node'
+
+    // Descend further into the tree.
+    path_stack << local_node.neighbor.clone()
+    local_node = lookup(local_node.neighbor[0])
+    local_path << local_node
+  }while( true )
 }
 
-task all {
-  dependsOn project
+def is_acyclic_q(root_node_labels ,boolean verbose = true){
+  // We are optimistic.
+  def return_value = 'acyclic'
+
+  // Initialize the DFS tree iterator.
+  def path_stack = []
+  path_stack << root_node_labels.clone()
+
+  // iterate over left side tree descent, not ideal as it starts at the
+  // root each time, but avoids complexity in the cycle detection logic.
+  do{
+    def result = is_acyclic_q_descend(path_stack ,verbose)
+    if(result == 'cycle_found') return_value = result
+
+    // increment the iterator to the next leftmost path
+    def top_list = path_stack[-1]
+    top_list.remove(0)
+    if( top_list.isEmpty() ) path_stack.pop()
+
+  }while( !path_stack.isEmpty() )
+
+  return return_value
 }
 
-task nothing {
-  doLast {
-    // useful for distinguishing between make syntax errors and build errors
+// LocalWords:  FN FPL DN DNL RuleNameListRegx RuleNameList PrintVisitorMethod
+// LocalWords:  PrintVisitor SyntaxAnnotate
+
+/*--------------------------------------------------------------------------------
+ run the build scripts
+   depends upon is_acyclic having already marked up the graph.
+
+Initialization:
+* visited: A set to keep track of visited nodes.
+* build_order: A list to store the nodes in the order they should be built.
+
+Depth-First Search (DFS):
+* The dfs function performs a depth-first traversal of the graph.
+* It looks up the node using the lookup function.
+* If the node has already been visited, it returns.
+* Otherwise, it marks the node as visited and recursively visits its neighbors.
+* After visiting all neighbors, it adds the node to the build_order list.
+
+Build Script Execution:
+* After the DFS traversal, the build_order list is reversed to ensure that leaf nodes are built first.
+*  The build scripts for each node are executed in the correct order.
+
+-- add date checks
+
+*/
+
+def run_build_scripts(root_node_labels ,boolean verbose = false){
+  def visited = [] as Set
+  def build_order = []
+
+  def dfs(node_label){
+    def node = lookup(node_label ,verbose)
+    if( !node ) return
+
+    if( node.label in visited ) return
+    visited << node.label
+
+    node.neighbor.each{ neighbor_label ->
+      dfs(neighbor_label)
+    }
+
+    build_order << node
+  }
+
+  root_node_labels.each{ root_label ->
+    dfs(root_label)
+  }
+
+  build_order.reverse().each{ node ->
+    if( node.build ){
+      println "Running build script for ${node.label}"
+      node.build(node ,node.neighbor)
+    }
   }
 }
 
-tasks.withType(Exec) {
-  doFirst {
-    println "Executing $name"
+// Example usage
+def root_node_labels = ["ANTLR_OUT_FL" ,"RuleNameList"]
+run_build_scripts(root_node_labels ,true)
+
+
+def run_build_scripts(root_node_labels ,boolean verbose = false){
+  if( root_node_labels.isEmpty() ) return
+
+  def visited = [] as Set
+  def build_order = []
+  def stack = []
+
+  root_node_labels.each{ root_label ->
+    stack << root_label
+  }
+
+  do{
+    def node_label = stack.pop()
+    def node = lookup(node_label ,verbose)
+    if( !node ) continue
+
+    if( node.label in visited ) continue
+    visited << node.label
+
+    node.neighbor.each{ neighbor_label ->
+      stack << neighbor_label
+    }
+
+    build_order << node
+  }while( !stack.isEmpty() )
+
+  build_order.reverse().each{ node ->
+    if( node.build ){
+      println "Running build script for ${node.label}"
+      node.build(node ,node.neighbor)
+    }
   }
 }
+
+// Example usage
+def root_node_labels = ["ANTLR_OUT_FL" ,"RuleNameList"]
+run_build_scripts(root_node_labels ,true)
index ba97b07..036961a 100755 (executable)
@@ -36,6 +36,7 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
   echo "This script must be sourced, not executed. Exiting."
   return 1
 fi
+export ENV_BUILD_VERSION="0.2"
 
 #--------------------------------------------------------------------------------
 # programs to be built by make project-all (or more simply `make`)
@@ -104,7 +105,7 @@ export CLASSPATH="${CLASSPATH}:$ANTLR_JAR"
 #--------------------------------------------------------------------------------
 # misc
 #
-export TEMP_DIR="$DEVELOPER_HOME"/temporary
+export TEMP_DIR="$DEVELOPER_HOME"/Erebus
 
 #--------------------------------------------------------------------------------
 # ANTLR files
diff --git a/developer/javac/leaf/ANTLR_OUT_FL.java b/developer/javac/leaf/ANTLR_OUT_FL.java
new file mode 100644 (file)
index 0000000..f852af5
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+  Run the command with no arguments for a usage message.
+
+  Accepts an antlr grammar file name of the form: [path/]<name>[Lexer/Parser][.g4]
+
+  Prints a space-separated list of files antlr4 would output.
+
+  The <name>Lexer or <name>Parser suffix, or absence thereof, tell this program if
+  antlr would create lexer and parser files, or both.
+
+
+*/
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ANTLR_OUT_FL {
+
+  private static final String USAGE_MESSAGE = 
+    "Usage: ANTLR_OUT_FL <grammar-name> "
+    +" [-visitor (default)] [-no-visitor] "
+    +" [-listener] [-no-listener (default)] "
+    +" [-tokens] [-no-tokens (default)] "
+    +" [-path <path>]"
+    ;
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    boolean visitor = true;
+    boolean noListener = true;
+    boolean noTokens = true;
+    String outputPath = "";
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        case "-visitor":
+          visitor = true;
+          break;
+        case "-no-visitor":
+          visitor = false;
+          break;
+        case "-listener":
+          noListener = false;
+          break;
+        case "-no-listener":
+          noListener = true;
+          break;
+        case "-tokens":
+          noTokens = false;
+          break;
+        case "-no-tokens":
+          noTokens = true;
+          break;
+        case "-path":
+          // Ensure the next argument exists and isn't another option
+          if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
+            outputPath = args[++i];  // Get the next argument as the path
+            if (!outputPath.endsWith("/")) {
+              outputPath += "/";  // Ensure the path ends with a slash
+            }
+          } else {
+            System.err.println("expected argument after option: " + args[i]);
+            error = true;
+          }
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      System.exit(error ? 1 : 0);
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String grammarName = argList.get(0);
+
+    List<String> generatedFiles = generateFileList(grammarName, visitor, noListener, noTokens, outputPath);
+
+    // Print the files in a space-separated format on a single line
+    if (!generatedFiles.isEmpty()) {
+      System.out.print(generatedFiles.get(0)); // Print the first file
+      for (int i = 1; i < generatedFiles.size(); i++) {
+        System.out.print(" " + generatedFiles.get(i)); // Print space and each subsequent file
+      }
+    }
+    System.out.println(); // Print a newline at the end
+  }
+
+  public static List<String> generateFileList(String grammarName, boolean visitor, boolean noListener, boolean noTokens, String outputPath) {
+    String baseName = new File(grammarName).getName().replace(".g4", "");
+    List<String> fileList = new ArrayList<>();
+
+    // Determine if this is a lexer, parser, or both
+    boolean isLexer = baseName.endsWith("Lexer");
+    boolean isParser = baseName.endsWith("Parser");
+    boolean isCombined = !isLexer && !isParser;
+
+    if (isLexer || isCombined) {
+      // Lexer files
+      fileList.add(outputPath + baseName + "Lexer.java");
+      if (!noTokens) fileList.add(outputPath + baseName + "Lexer.tokens");
+    }
+
+    if (isParser || isCombined) {
+      // Parser files
+      fileList.add(outputPath + baseName + "Parser.java");
+      if (!noTokens) fileList.add(outputPath + baseName + ".tokens");
+
+      // Listener-related files
+      if (!noListener) {
+        fileList.add(outputPath + baseName + "Listener.java");
+        fileList.add(outputPath + baseName + "BaseListener.java");
+      }
+
+      // Visitor-related files
+      if (visitor) {
+        fileList.add(outputPath + baseName + "Visitor.java");
+        fileList.add(outputPath + baseName + "BaseVisitor.java");
+      }
+    }
+
+    return fileList;
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_Echo.java b/developer/javac/leaf/Arithmetic_Echo.java
new file mode 100644 (file)
index 0000000..8fadf28
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+Takes an 'Ariethemetic' grammar source file.  Parses it. Runs through the parse tree
+and recreates the source file.
+
+*/
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Arithmetic_Echo {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE =
+    "Usage: Arithmetic_Echo [-version] <source-file-path>";
+
+  public static void main(String[] args) throws IOException {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String inputFile = argList.get(0);
+    String input = Files.readString(Paths.get(inputFile));
+
+    try {
+      // Direct instantiation without reflection
+      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
+      CommonTokenStream tokens = new CommonTokenStream(lexer);
+      ArithmeticParser parser = new ArithmeticParser(tokens);
+
+      // Directly calling the start rule method
+      ParseTree tree = parser.program(); // Assuming 'program' is the start rule
+
+      Arithmetic_Echo_PrintVisitor visitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
+      String output = visitor.visit(tree);
+      System.out.println(output);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_Echo_PrintVisitor.java b/developer/javac/leaf/Arithmetic_Echo_PrintVisitor.java
new file mode 100644 (file)
index 0000000..488d54a
--- /dev/null
@@ -0,0 +1,31 @@
+import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+
+public class Arithmetic_Echo_PrintVisitor extends ArithmeticBaseVisitor<String> {
+  private final String[] ruleNames;
+
+  public Arithmetic_Echo_PrintVisitor(String[] ruleNames) {
+    this.ruleNames = ruleNames;
+  }
+
+  @Override
+  public String visitProgram(ArithmeticParser.ProgramContext ctx) {
+    return visit(ctx.expression());
+  }
+
+  @Override
+  public String visitExpression(ArithmeticParser.ExpressionContext ctx) {
+    if (ctx.INT() != null) {
+      return ctx.INT().getText();
+    } else if (ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(")) {
+      // Handle parentheses
+      return visit(ctx.expression(0));  // Remove the extra parentheses
+    } else {
+      String left = visit(ctx.expression(0));
+      String right = visit(ctx.expression(1));
+      String operator = ctx.getChild(1).getText();
+      return "(" + left + " " + operator + " " + right + ")";
+    }
+  }
+
+}
+
diff --git a/developer/javac/leaf/Arithmetic_Echo__Test.java b/developer/javac/leaf/Arithmetic_Echo__Test.java
new file mode 100644 (file)
index 0000000..8e670b1
--- /dev/null
@@ -0,0 +1,134 @@
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Arithmetic_Echo__Test {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE =
+    "Usage: Arithmetic_Echo__Test [-version]";
+
+  public static void main(String[] args) {
+    // if (args.length == 0) {
+    //   System.err.println(USAGE_MESSAGE);
+    //   System.exit(1);
+    // }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 0) {
+      System.err.println("This program takes no arguments.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    Map<String, Boolean> tests = new HashMap<>();
+    tests.put("Arithmetic_Echo_0", Arithmetic_Echo_0());
+    tests.put("Arithmetic_Echo_1", Arithmetic_Echo_1());
+    tests.put("Arithmetic_Echo_2", Arithmetic_Echo_2());
+    tests.put("Arithmetic_Echo_3", Arithmetic_Echo_3());
+    tests.put("Arithmetic_Echo_4", Arithmetic_Echo_4());
+
+    TestBench.runTests(tests);
+  }
+
+  public static boolean Arithmetic_Echo_0() {
+    // Simple smoke test
+    try {
+      String input = "3 + 5";
+      String expectedOutput = "(3 + 5)";
+      String actualOutput = runSyntax(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
+  public static boolean Arithmetic_Echo_1() {
+    // Test with multiplication
+    try {
+      String input = "2 * 3";
+      String expectedOutput = "(2 * 3)";
+      String actualOutput = runSyntax(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
+  public static boolean Arithmetic_Echo_2() {
+    // Test with parentheses
+    try {
+      String input = "2 * (3 + 4)";
+      String expectedOutput = "(2 * (3 + 4))";
+      String actualOutput = runSyntax(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
+  public static boolean Arithmetic_Echo_3() {
+    // Test with division
+    try {
+      String input = "10 / 2";
+      String expectedOutput = "(10 / 2)";
+      String actualOutput = runSyntax(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
+  public static boolean Arithmetic_Echo_4() {
+    // Test with complex expression
+    try {
+      String input = "3 + 5 * (10 - 4)";
+      String expectedOutput = "(3 + (5 * (10 - 4)))";
+      String actualOutput = runSyntax(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
+  private static String runSyntax(String input) throws Exception {
+    Lexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
+    CommonTokenStream tokens = new CommonTokenStream(lexer);
+    ArithmeticParser parser = new ArithmeticParser(tokens);
+    Method startRule = parser.getClass().getMethod("program");
+    ParseTree tree = (ParseTree) startRule.invoke(parser);
+
+    Arithmetic_Echo_PrintVisitor visitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
+    return visitor.visit(tree);
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_Swap.java b/developer/javac/leaf/Arithmetic_Swap.java
new file mode 100644 (file)
index 0000000..58e1caf
--- /dev/null
@@ -0,0 +1,69 @@
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Arithmetic_Swap {
+  private static final String USAGE_MESSAGE =
+    "Usage: Arithmetic_Swap [-version] <source-file-path>";
+
+  public static void main(String[] args) throws IOException {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (String arg : args) {
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if (version) {
+      System.out.println("version 0.1");
+      System.exit(error ? 1 : 0);
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if (error) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String inputFile = argList.get(0);
+    String input = Files.readString(Paths.get(inputFile));
+
+    try {
+      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
+      CommonTokenStream tokens = new CommonTokenStream(lexer);
+      ArithmeticParser parser = new ArithmeticParser(tokens);
+      
+      ParseTree tree = parser.program();
+
+      Arithmetic_SwapVisitor swapVisitor = new Arithmetic_SwapVisitor();
+      ParseTree transformedTree = swapVisitor.visit(tree);
+
+      Arithmetic_Echo_PrintVisitor printVisitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
+      String output = printVisitor.visit(transformedTree);
+
+      System.out.println(output);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_SwapVisitor.java b/developer/javac/leaf/Arithmetic_SwapVisitor.java
new file mode 100644 (file)
index 0000000..f108735
--- /dev/null
@@ -0,0 +1,50 @@
+import org.antlr.v4.runtime.tree.*;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.*;
+
+public class Arithmetic_SwapVisitor extends AbstractParseTreeVisitor<ParseTree> {
+
+    @Override
+    public ParseTree visit(ParseTree tree) {
+        if (tree instanceof ParserRuleContext) {
+            ParserRuleContext ctx = (ParserRuleContext) tree;
+            ParserRuleContext newCtx = new ParserRuleContext();
+
+            // Recursively visit all children and add them to the new context
+            for (int i = 0; i < ctx.getChildCount(); i++) {
+                ParseTree child = ctx.getChild(i);
+                ParseTree visitedChild = this.visit(child);
+                
+                // Add child if it's a valid type
+                if (visitedChild instanceof ParserRuleContext) {
+                    newCtx.addChild((ParserRuleContext) visitedChild);
+                } else if (visitedChild instanceof TerminalNode) {
+                    newCtx.addChild((TerminalNode) visitedChild);
+                }
+            }
+            return newCtx;
+        } else if (tree instanceof TerminalNode) {
+            TerminalNode node = (TerminalNode) tree;
+            // Swap operators based on text
+            switch (node.getText()) {
+                case "+":
+                    return createTerminalNode(node, ArithmeticParser.MINUS); // Swap + with -
+                case "-":
+                    return createTerminalNode(node, ArithmeticParser.PLUS);  // Swap - with +
+                case "*":
+                    return createTerminalNode(node, ArithmeticParser.DIVIDE); // Swap * with /
+                case "/":
+                    return createTerminalNode(node, ArithmeticParser.MULTIPLY); // Swap / with *
+                default:
+                    return node; // Return node as is for non-operator tokens
+            }
+        }
+        return null;
+    }
+
+    // Helper method to create a new TerminalNode with the swapped token
+    private TerminalNode createTerminalNode(TerminalNode oldNode, int newTokenType) {
+        Token newToken = new CommonToken(newTokenType, oldNode.getText());
+        return new TerminalNodeImpl(newToken);
+    }
+}
diff --git a/developer/javac/leaf/Arithmetic_SyntaxAnnotate.java b/developer/javac/leaf/Arithmetic_SyntaxAnnotate.java
new file mode 100644 (file)
index 0000000..0516db6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+Takes an 'Ariethemetic' grammar source file.  Parses it. Outputs an annotated
+version of the source file while labeling what parts of the grammar the syntax
+objects belong to.  Note the -pp option.
+
+*/
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Arithmetic_SyntaxAnnotate {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE = 
+    "Usage: Arithmetic_SyntaxAnnotate [-version] [-pp] <source-file>";
+
+  public static void main(String[] args) throws IOException {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    boolean pretty_print = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        case "-pp":
+          pretty_print = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String input_file = argList.get(0);
+    String input = Files.readString(Paths.get(input_file));
+
+    try {
+      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
+      CommonTokenStream tokens = new CommonTokenStream(lexer);
+      ArithmeticParser parser = new ArithmeticParser(tokens);
+      ParseTree tree = parser.program();
+
+      Arithmetic_SyntaxAnnotate_PrintVisitor visitor = 
+        new Arithmetic_SyntaxAnnotate_PrintVisitor(parser.getRuleNames(), pretty_print);
+      String output = visitor.visit(tree);
+      System.out.println(output);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_SyntaxAnnotate_PrintVisitor.java b/developer/javac/leaf/Arithmetic_SyntaxAnnotate_PrintVisitor.java
new file mode 100644 (file)
index 0000000..9831e54
--- /dev/null
@@ -0,0 +1,62 @@
+import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+
+public class Arithmetic_SyntaxAnnotate_PrintVisitor extends ArithmeticBaseVisitor<String>{
+  private final String[] rule_names;
+  private final boolean pretty_print;
+
+  public Arithmetic_SyntaxAnnotate_PrintVisitor(String[] rule_names, boolean pretty_print){
+    this.rule_names = rule_names;
+    this.pretty_print = pretty_print;
+  }
+
+  private String indent(int level){
+    return "  ".repeat(level);
+  }
+
+  @Override
+  public String visitProgram(ArithmeticParser.ProgramContext ctx){
+    if(pretty_print){
+      StringBuilder result = new StringBuilder();
+      result.append("program\n").append(visitExpression(ctx.expression(), 1));
+      return result.toString();
+    }else{
+      return "program(" + visit(ctx.expression()) + ")";
+    }
+  }
+
+  @Override
+  public String visitExpression(ArithmeticParser.ExpressionContext ctx){
+    return visitExpression(ctx, 0);
+  }
+
+  private String visitExpression(ArithmeticParser.ExpressionContext ctx, int indent_level){
+    StringBuilder result = new StringBuilder();
+    if(pretty_print){
+      result.append(indent(indent_level)).append("expression(\n");
+      if( ctx.INT() != null ){
+        result.append(indent(indent_level + 1)).append("INT(").append(ctx.INT().getText()).append(")\n");
+      }else if( ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(") ){
+        result.append(indent(indent_level + 1)).append("(\n");
+        result.append(visitExpression(ctx.expression(0), indent_level + 2));
+        result.append(indent(indent_level + 1)).append(")\n");
+      }else{
+        result.append(visitExpression(ctx.expression(0), indent_level + 1));
+        result.append(indent(indent_level + 1)).append("operator(").append(ctx.getChild(1).getText()).append(")\n");
+        result.append(visitExpression(ctx.expression(1), indent_level + 1));
+      }
+      result.append(indent(indent_level)).append(")\n");
+    }else{
+      if( ctx.INT() != null ){
+        result.append("INT(").append(ctx.INT().getText()).append(")");
+      }else if( ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(") ){
+        result.append("(").append(visit(ctx.expression(0))).append(")");
+      }else{
+        String left = visit(ctx.expression(0));
+        String right = visit(ctx.expression(1));
+        String operator = "operator(" + ctx.getChild(1).getText() + ")";
+        result.append("expression(").append(left).append(" ").append(operator).append(" ").append(right).append(")");
+      }
+    }
+    return result.toString();
+  }
+}
diff --git a/developer/javac/leaf/Arithmetic_SyntaxAnnotate__Test.java b/developer/javac/leaf/Arithmetic_SyntaxAnnotate__Test.java
new file mode 100644 (file)
index 0000000..a80b690
--- /dev/null
@@ -0,0 +1,125 @@
+
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Arithmetic_SyntaxAnnotate__Test {
+
+  public static boolean Arithmetic_SyntaxAnnotate_0() {
+    return runTest(
+      "Arithmetic_SyntaxAnnotate__Test_0.txt"
+     ,"program(expression(INT(3) operator(+) INT(5)))"
+     );
+  }
+
+  public static boolean Arithmetic_SyntaxAnnotate_1() {
+    return runTest(
+      "Arithmetic_SyntaxAnnotate__Test_1.txt"
+      ,"program(expression(INT(3) operator(+) INT(5)))"
+   );
+  }
+
+  public static boolean Arithmetic_SyntaxAnnotate_2() {
+    return runTest(
+      "Arithmetic_SyntaxAnnotate__Test_2.txt" 
+      ,"program(expression(INT(2) operator(*) (expression(INT(3) operator(+) INT(4)))))"
+      );
+  }
+
+  public static boolean Arithmetic_SyntaxAnnotate_3() {
+    return runTest(
+      "Arithmetic_SyntaxAnnotate__Test_3.txt" 
+      ,"program(expression(INT(10) operator(/) INT(2)))"
+      );
+  }
+
+  public static boolean Arithmetic_SyntaxAnnotate_4() {
+    return runTest(
+      "Arithmetic_SyntaxAnnotate__Test_4.txt" 
+      ,"program(expression(INT(3) operator(+) expression(INT(5) operator(*) (expression(INT(10) operator(-) INT(4))))))"
+      );
+  }
+
+  private static boolean runTest(String filename ,String expectedOutput) {
+    try {
+      String input = Files.readString(Paths.get(filename));
+      String actualOutput = runSyntaxAnnotate(input);
+      return expectedOutput.equals(actualOutput);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  private static String runSyntaxAnnotate(String input) throws Exception {
+    Lexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
+    CommonTokenStream tokens = new CommonTokenStream(lexer);
+    ArithmeticParser parser = new ArithmeticParser(tokens);
+    ParseTree tree = parser.program(); // Directly calling the start rule method
+
+    Arithmetic_SyntaxAnnotate_PrintVisitor visitor = new Arithmetic_SyntaxAnnotate_PrintVisitor(parser.getRuleNames() ,false);
+    return visitor.visit(tree);
+  }
+
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE = 
+    "Usage: Arithmetic_SyntaxAnnotate__Test [-version]";
+
+  public static void main(String[] args) {
+    // if (args.length == 0) {
+    //   System.err.println(USAGE_MESSAGE);
+    //   System.exit(1);
+    // }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 0) {
+      System.err.println("This program takes no arguments.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    // Use LinkedHashMap to maintain order of test results
+    Map<String, Boolean> tests = new LinkedHashMap<>();
+    tests.put("Arithmetic_SyntaxAnnotate_0", Arithmetic_SyntaxAnnotate_0());
+    tests.put("Arithmetic_SyntaxAnnotate_1", Arithmetic_SyntaxAnnotate_1());
+    tests.put("Arithmetic_SyntaxAnnotate_2", Arithmetic_SyntaxAnnotate_2());
+    tests.put("Arithmetic_SyntaxAnnotate_3", Arithmetic_SyntaxAnnotate_3());
+    tests.put("Arithmetic_SyntaxAnnotate_4", Arithmetic_SyntaxAnnotate_4());
+
+    TestBench.runTests(tests);
+  }
+
+}
+
diff --git a/developer/javac/leaf/RuleNameList.java b/developer/javac/leaf/RuleNameList.java
new file mode 100644 (file)
index 0000000..c9b727c
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Accepts an grammar name (not a file path or file name) and outputs the rule
+  names found in the grammar.  
+
+  RuleNameList does not run antlr to build the grammar files, that must have
+  been done separately before this program is run.
+
+  RuleNameList produces a more reliable list than does RuleNameListRegx.
+
+  RuleNameList does not output terminal symbols (the lexer tokens).
+
+  Usage: ANTLRv4_RuleNames <input-file>
+*/
+
+import org.antlr.v4.runtime.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RuleNameList {
+
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE =
+    "Usage: RuleNameList"
+    +" [-version]"
+    +" [-rule (default)] [-no-rule]"
+    +" [-token] [-no-token (default)]"
+    +" <grammar-name>"
+    ;
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    boolean printRules = true;
+    boolean printTokens = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        case "-rule":
+          printRules = true;
+          break;
+        case "-no-rule":
+          printRules = false;
+          break;
+        case "-token":
+          printTokens = true;
+          break;
+        case "-no-token":
+          printTokens = false;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String grammarName = argList.get(0);
+    // in case the user provided a path instead of a name:
+    grammarName = Paths.get(grammarName).getFileName().toString().replace(".g4", "");
+
+    try {
+      // Dynamically load the appropriate lexer and parser
+      Class<?> lexerClass = Class.forName(grammarName + "Lexer");
+      Class<?> parserClass = Class.forName(grammarName + "Parser");
+
+      // Create instances of the lexer and parser
+      Lexer lexer = (Lexer) lexerClass.getConstructor(CharStream.class).newInstance(CharStreams.fromString(""));
+      CommonTokenStream tokens = new CommonTokenStream(lexer);
+      Parser parser = (Parser) parserClass.getConstructor(TokenStream.class).newInstance(tokens);
+
+      // Get the rule names from the parser
+      List<String> ruleNames = List.of(parser.getRuleNames());
+
+      // Get the token names from the lexer
+      List<String> tokenNames = List.of(lexer.getTokenNames());
+
+      // Print the rule names if requested
+      if (printRules) {
+        if (printTokens) {
+          System.out.println("#----------------------------------------");
+          System.out.println("# Rule names found in the grammar:");
+        }
+        for (String ruleName : ruleNames) {
+          System.out.println(ruleName);
+        }
+      }
+
+      // Print the token names if requested
+      if (printTokens) {
+        if (printRules) {
+          System.out.println("#----------------------------------------");
+          System.out.println("# Token names found in the grammar:");
+        }
+        for (String tokenName : tokenNames) {
+          System.out.println(tokenName);
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/developer/javac/leaf/RuleNameListRegx.java b/developer/javac/leaf/RuleNameListRegx.java
new file mode 100644 (file)
index 0000000..36ffb2b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+Directly reads an ANTLR grammar file, a `.g4` file, and lists all the rules found in it.
+
+*/
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RuleNameListRegx {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE =
+    "Usage: RuleNameListRegx [-version] <path-to-g4-file>";
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    boolean pretty_print = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        case "-pp":
+          pretty_print = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }
+    }
+    if (argList.size() != 1) {
+      System.err.println("Expected exactly one non-option argument.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String filePath = argList.get(0);
+
+    try {
+      Set<String> ruleNames = new HashSet<>();
+      BufferedReader br = new BufferedReader(new FileReader(filePath));
+      StringBuilder content = new StringBuilder();
+      String line;
+      while ((line = br.readLine()) != null) {
+        content.append(line).append("\n");
+      }
+
+      // Updated pattern to handle multi-line rules
+      Pattern rulePattern = Pattern.compile("(?m)^\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*:");
+
+      Matcher matcher = rulePattern.matcher(content.toString());
+      while (matcher.find()) {
+        ruleNames.add(matcher.group(1));
+      }
+
+      System.out.println("Extracted Rules:");
+      for (String rule : ruleNames) {
+        System.out.println(rule);
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/developer/javac/leaf/StringUtils.java b/developer/javac/leaf/StringUtils.java
new file mode 100644 (file)
index 0000000..774e253
--- /dev/null
@@ -0,0 +1,18 @@
+public class StringUtils {
+
+    private static int spacesPerIndentLevel = 2; // Default to 2 spaces per indent level
+
+    public static void setSpacesPerIndentLevel(int spaces) {
+        spacesPerIndentLevel = spaces;
+    }
+
+    public static String indentString(String template, int indentLevel) {
+        String indent = " ".repeat(spacesPerIndentLevel * indentLevel);
+        String[] lines = template.split("\n");
+        StringBuilder indentedTemplate = new StringBuilder();
+        for (String line : lines) {
+            indentedTemplate.append(indent).append(line).append("\n");
+        }
+        return indentedTemplate.toString();
+    }
+}
diff --git a/developer/javac/leaf/Synthesize_SyntaxAnnotate.java b/developer/javac/leaf/Synthesize_SyntaxAnnotate.java
new file mode 100644 (file)
index 0000000..6f002f1
--- /dev/null
@@ -0,0 +1,166 @@
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Synthesize_SyntaxAnnotate {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE = 
+    "Usage: Synthesize_SyntaxAnnotate [-version] <grammar-name> <output-file-path>";
+
+  public static void main(String[] args) throws IOException {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 2) {
+      System.err.println("Expected exactly two non-option arguments.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String grammarName = argList.get(0);
+    // in case the user provided a path instead of a name:
+    grammarName = Paths.get(grammarName).getFileName().toString().replace(".g4", "");
+
+    String outputFile = argList.get(1);
+
+    synthesizeSyntaxAnnotateClass(grammarName, outputFile);
+  }
+
+  private static void synthesizeSyntaxAnnotateClass(String grammarName, String outputFile) throws IOException {
+    String className = grammarName + "_SyntaxAnnotate";
+    String lexerName = grammarName + "Lexer";
+    String parserName = grammarName + "Parser";
+    String visitorName = grammarName + "_SyntaxAnnotate_PrintVisitor";
+
+    // Template for the SyntaxAnnotate class
+    String classTemplate = """
+      /* This file generated by Synthesize_SyntaxAnnotate given the grammar 
+         name: ____4_.
+         
+         SyntaxAnnotate programs accept a source file, then echo the source file with
+         syntax annotation. Synthesize_SyntaxAnnotate produces a SyntaxAnnotate program
+         for a specific grammar.
+       */
+      import org.antlr.v4.runtime.*;
+      import org.antlr.v4.runtime.tree.*;
+      import java.io.IOException;
+      import java.nio.file.Files;
+      import java.nio.file.Paths;
+      import java.util.ArrayList;
+      import java.util.List;
+
+      public class ____0_ {
+        // Constant for the usage message
+        private static final String USAGE_MESSAGE =
+          "Usage: ____0_ [-version] [-pp] <source-file-path>";
+
+        public static void main(String[] args) throws IOException {
+          if (args.length == 0) {
+            System.err.println(USAGE_MESSAGE);
+            System.exit(1);
+          }
+          boolean error = false;
+          boolean version = false;
+          boolean pretty_print = false;
+          List<String> argList = new ArrayList<>();
+          for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("-")) {
+              switch (arg) {
+              case "-version":
+                version = true;
+                break;
+              case "-pp":
+                pretty_print = true;
+                break;
+              default:
+                System.err.println("Unrecognized option: " + arg);
+                error = true;
+              }
+            } else {
+              argList.add(arg);
+            }
+          }
+          if(version){
+            System.out.println("version 0.1");
+            if(error){
+              System.exit(1);
+            }else{
+              System.exit(0);
+            }        
+          }
+          if (argList.size() != 1) {
+            System.err.println("Expected exactly one non-option argument.");
+            error = true;
+          }
+          if(error){
+            System.err.println(USAGE_MESSAGE);
+            System.exit(1);
+          }
+
+          String input_file = argList.get(0);
+          String input = Files.readString(Paths.get(input_file));
+
+          try {
+            ____1_ lexer = new ____1_(CharStreams.fromString(input));
+            CommonTokenStream tokens = new CommonTokenStream(lexer);
+            ____2_ parser = new ____2_(tokens);
+            ParseTree tree = parser.program();
+
+            ____3_ visitor = new ____3_(parser.getRuleNames(), pretty_print);
+            String output = visitor.visit(tree);
+            System.out.println(output);
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      }
+      """;
+
+    // Fill in the blanks in the template
+    classTemplate = classTemplate.replace("____0_", className);
+    classTemplate = classTemplate.replace("____1_", lexerName);
+    classTemplate = classTemplate.replace("____2_", parserName);
+    classTemplate = classTemplate.replace("____3_", visitorName);
+    classTemplate = classTemplate.replace("____4_", grammarName);
+
+    // Write the synthesized class to the output file
+    Files.writeString(Paths.get(outputFile), classTemplate);
+  }
+}
+
+//  LocalWords:  SyntaxAnnotate
diff --git a/developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitor.java b/developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitor.java
new file mode 100644 (file)
index 0000000..ae508b0
--- /dev/null
@@ -0,0 +1,117 @@
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.io.PrintWriter;
+
+public class Synthesize_SyntaxAnnotate_PrintVisitor {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE = 
+    "Usage: Synthesize_SyntaxAnnotate_PrintVisitor"
+    +" [-version]"
+    +" <g4-grammar-file-path> <outputFile> [indent-level (default 0)]"
+    ;
+
+  public static void main(String[] args) throws IOException {
+  if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    int indentLevel = 0;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if (version) {
+      System.out.println("Version 0.1");
+      if (error) {
+        System.exit(1);
+      } else {
+        System.exit(0);
+      }
+    }
+    if (argList.size() < 2 || argList.size() > 3) {
+      System.err.println("Expected two or three non-option arguments.");
+      error = true;
+    }
+    if (error) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String grammarFilePath = argList.get(0);
+    String outputFile      = argList.get(1);
+    if (argList.size() == 3) {
+      indentLevel = Integer.parseInt(argList.get(2));
+    }
+
+    String grammarName = Paths.get(grammarFilePath).getFileName().toString().replace(".g4", "");
+    String parserName = grammarName + "Parser";
+    String visitorClassName = grammarName + "_SyntaxAnnotate_PrintVisitor";
+
+    // Parse the .g4 file
+    CharStream input = CharStreams.fromFileName(grammarFilePath);
+    ANTLRv4Lexer lexer = new ANTLRv4Lexer(input);
+    CommonTokenStream tokens = new CommonTokenStream(lexer);
+    ANTLRv4Parser parser = new ANTLRv4Parser(tokens);
+
+    // Extract rules
+    ParseTree tree = parser.grammarSpec();
+    List<String> ruleNames = extractRuleNames(parser);
+
+    // Synthesize the print methods
+    StringBuilder printMethods = new StringBuilder();
+    for (String ruleName : ruleNames) {
+      printMethods.append(Synthesize_SyntaxAnnotate_PrintVisitorMethod.synthesizePrintMethod(parserName, ruleName, indentLevel + 1));
+    }
+
+    // Template for the PrintVisitor class
+    String classTemplate = """
+      /* This file synthesized by Synthesize_SyntaxAnnotate_PrintVisitor.
+      */
+      import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+
+      public class ____0_ extends AbstractParseTreeVisitor<String> {
+        private final String[] ruleNames;
+
+        public ____0_(String[] ruleNames) {
+          this.ruleNames = ruleNames;
+        }
+
+        ____1_
+      }
+      """;
+
+    classTemplate = classTemplate.replace("____0_", visitorClassName);
+    classTemplate = classTemplate.replace("____1_", printMethods.toString());
+
+    try (PrintWriter writer = new PrintWriter(outputFile)) {
+      writer.print(classTemplate);
+    }
+  }
+
+  private static List<String> extractRuleNames(Parser parser) {
+    // Extract rule names from the parser
+    return Arrays.asList(parser.getRuleNames());
+  }
+}
+
+//  LocalWords:  SyntaxAnnotate PrintVisitor
diff --git a/developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java b/developer/javac/leaf/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java
new file mode 100644 (file)
index 0000000..35394bb
--- /dev/null
@@ -0,0 +1,90 @@
+import java.util.ArrayList;
+import java.util.List;
+import java.io.PrintWriter;
+
+public class Synthesize_SyntaxAnnotate_PrintVisitorMethod {
+  // Constant for the usage message
+  private static final String USAGE_MESSAGE = 
+    "Usage: Synthesize_SyntaxAnnotate_PrintVisitorMethod"
+    + " [-version]"
+    +" <grammar-name> <g4-rule-name> <output-file>"
+    ;
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+    boolean error = false;
+    boolean version = false;
+    List<String> argList = new ArrayList<>();
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (arg.startsWith("-")) {
+        switch (arg) {
+        case "-version":
+          version = true;
+          break;
+        default:
+          System.err.println("Unrecognized option: " + arg);
+          error = true;
+        }
+      } else {
+        argList.add(arg);
+      }
+    }
+    if(version){
+      System.out.println("version 0.1");
+      if(error){
+        System.exit(1);
+      }else{
+        System.exit(0);
+      }        
+    }
+    if (argList.size() != 3) {
+      System.err.println("Expected exactly three non-option arguments.");
+      error = true;
+    }
+    if(error){
+      System.err.println(USAGE_MESSAGE);
+      System.exit(1);
+    }
+
+    String grammarName = argList.get(0);
+    String ruleName    = argList.get(1);
+    String outputFile  = argList.get(2);
+
+    String parserName = grammarName + "Parser";
+    
+    try {
+      PrintWriter writer = new PrintWriter(outputFile);
+      // start at indent level 0
+      writer.print(synthesizePrintMethod(parserName, ruleName, 0)); 
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  public static String synthesizePrintMethod(String parserName, String ruleName, int indentLevel) {
+    // Template for the print method using text blocks
+    String template = """
+      public String visit____0_ (____1_.____0_Context ctx) {
+        StringBuilder result = new StringBuilder();
+        result.append("____0_(");
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+          if (i > 0) result.append(", ");
+          result.append(visit(ctx.getChild(i)));
+        }
+        result.append(")");
+        return result.toString();
+      }
+      """;
+
+    // Fill in the blanks in the template
+    template = template.replace("____0_", ruleName);
+    template = template.replace("____1_", parserName);
+
+    // Indent the template
+    return StringUtils.indentString(template, indentLevel);
+  }
+}
diff --git a/developer/javac/leaf/TestBench.java b/developer/javac/leaf/TestBench.java
new file mode 100644 (file)
index 0000000..8bdcc67
--- /dev/null
@@ -0,0 +1,28 @@
+import java.util.Map;
+
+public class TestBench {
+
+    public static void runTests(Map<String, Boolean> tests) {
+        int totalTests = tests.size();
+        int passedTests = 0;
+        int failedTests = 0;
+
+        for (Map.Entry<String, Boolean> test : tests.entrySet()) {
+            try {
+                if (test.getValue()) {
+                    passedTests++;
+                } else {
+                    System.out.println("failed: " + test.getKey());
+                    failedTests++;
+                }
+            } catch (Exception e) {
+                System.out.println("failed: " + test.getKey());
+                failedTests++;
+            }
+        }
+
+        System.out.println("Total tests run: " + totalTests);
+        System.out.println("Total tests passed: " + passedTests);
+        System.out.println("Total tests failed: " + failedTests);
+    }
+}
diff --git a/developer/javac/primary/ANTLR_OUT_FL.java b/developer/javac/primary/ANTLR_OUT_FL.java
deleted file mode 100644 (file)
index f852af5..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
-  Run the command with no arguments for a usage message.
-
-  Accepts an antlr grammar file name of the form: [path/]<name>[Lexer/Parser][.g4]
-
-  Prints a space-separated list of files antlr4 would output.
-
-  The <name>Lexer or <name>Parser suffix, or absence thereof, tell this program if
-  antlr would create lexer and parser files, or both.
-
-
-*/
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ANTLR_OUT_FL {
-
-  private static final String USAGE_MESSAGE = 
-    "Usage: ANTLR_OUT_FL <grammar-name> "
-    +" [-visitor (default)] [-no-visitor] "
-    +" [-listener] [-no-listener (default)] "
-    +" [-tokens] [-no-tokens (default)] "
-    +" [-path <path>]"
-    ;
-
-  public static void main(String[] args) {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    boolean visitor = true;
-    boolean noListener = true;
-    boolean noTokens = true;
-    String outputPath = "";
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        case "-visitor":
-          visitor = true;
-          break;
-        case "-no-visitor":
-          visitor = false;
-          break;
-        case "-listener":
-          noListener = false;
-          break;
-        case "-no-listener":
-          noListener = true;
-          break;
-        case "-tokens":
-          noTokens = false;
-          break;
-        case "-no-tokens":
-          noTokens = true;
-          break;
-        case "-path":
-          // Ensure the next argument exists and isn't another option
-          if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
-            outputPath = args[++i];  // Get the next argument as the path
-            if (!outputPath.endsWith("/")) {
-              outputPath += "/";  // Ensure the path ends with a slash
-            }
-          } else {
-            System.err.println("expected argument after option: " + args[i]);
-            error = true;
-          }
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      System.exit(error ? 1 : 0);
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String grammarName = argList.get(0);
-
-    List<String> generatedFiles = generateFileList(grammarName, visitor, noListener, noTokens, outputPath);
-
-    // Print the files in a space-separated format on a single line
-    if (!generatedFiles.isEmpty()) {
-      System.out.print(generatedFiles.get(0)); // Print the first file
-      for (int i = 1; i < generatedFiles.size(); i++) {
-        System.out.print(" " + generatedFiles.get(i)); // Print space and each subsequent file
-      }
-    }
-    System.out.println(); // Print a newline at the end
-  }
-
-  public static List<String> generateFileList(String grammarName, boolean visitor, boolean noListener, boolean noTokens, String outputPath) {
-    String baseName = new File(grammarName).getName().replace(".g4", "");
-    List<String> fileList = new ArrayList<>();
-
-    // Determine if this is a lexer, parser, or both
-    boolean isLexer = baseName.endsWith("Lexer");
-    boolean isParser = baseName.endsWith("Parser");
-    boolean isCombined = !isLexer && !isParser;
-
-    if (isLexer || isCombined) {
-      // Lexer files
-      fileList.add(outputPath + baseName + "Lexer.java");
-      if (!noTokens) fileList.add(outputPath + baseName + "Lexer.tokens");
-    }
-
-    if (isParser || isCombined) {
-      // Parser files
-      fileList.add(outputPath + baseName + "Parser.java");
-      if (!noTokens) fileList.add(outputPath + baseName + ".tokens");
-
-      // Listener-related files
-      if (!noListener) {
-        fileList.add(outputPath + baseName + "Listener.java");
-        fileList.add(outputPath + baseName + "BaseListener.java");
-      }
-
-      // Visitor-related files
-      if (visitor) {
-        fileList.add(outputPath + baseName + "Visitor.java");
-        fileList.add(outputPath + baseName + "BaseVisitor.java");
-      }
-    }
-
-    return fileList;
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_Echo.java b/developer/javac/primary/Arithmetic_Echo.java
deleted file mode 100644 (file)
index 8fadf28..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Takes an 'Ariethemetic' grammar source file.  Parses it. Runs through the parse tree
-and recreates the source file.
-
-*/
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Arithmetic_Echo {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE =
-    "Usage: Arithmetic_Echo [-version] <source-file-path>";
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String inputFile = argList.get(0);
-    String input = Files.readString(Paths.get(inputFile));
-
-    try {
-      // Direct instantiation without reflection
-      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
-      CommonTokenStream tokens = new CommonTokenStream(lexer);
-      ArithmeticParser parser = new ArithmeticParser(tokens);
-
-      // Directly calling the start rule method
-      ParseTree tree = parser.program(); // Assuming 'program' is the start rule
-
-      Arithmetic_Echo_PrintVisitor visitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
-      String output = visitor.visit(tree);
-      System.out.println(output);
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_Echo_PrintVisitor.java b/developer/javac/primary/Arithmetic_Echo_PrintVisitor.java
deleted file mode 100644 (file)
index 488d54a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
-
-public class Arithmetic_Echo_PrintVisitor extends ArithmeticBaseVisitor<String> {
-  private final String[] ruleNames;
-
-  public Arithmetic_Echo_PrintVisitor(String[] ruleNames) {
-    this.ruleNames = ruleNames;
-  }
-
-  @Override
-  public String visitProgram(ArithmeticParser.ProgramContext ctx) {
-    return visit(ctx.expression());
-  }
-
-  @Override
-  public String visitExpression(ArithmeticParser.ExpressionContext ctx) {
-    if (ctx.INT() != null) {
-      return ctx.INT().getText();
-    } else if (ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(")) {
-      // Handle parentheses
-      return visit(ctx.expression(0));  // Remove the extra parentheses
-    } else {
-      String left = visit(ctx.expression(0));
-      String right = visit(ctx.expression(1));
-      String operator = ctx.getChild(1).getText();
-      return "(" + left + " " + operator + " " + right + ")";
-    }
-  }
-
-}
-
diff --git a/developer/javac/primary/Arithmetic_Echo__Test.java b/developer/javac/primary/Arithmetic_Echo__Test.java
deleted file mode 100644 (file)
index 8e670b1..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Arithmetic_Echo__Test {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE =
-    "Usage: Arithmetic_Echo__Test [-version]";
-
-  public static void main(String[] args) {
-    // if (args.length == 0) {
-    //   System.err.println(USAGE_MESSAGE);
-    //   System.exit(1);
-    // }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 0) {
-      System.err.println("This program takes no arguments.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    Map<String, Boolean> tests = new HashMap<>();
-    tests.put("Arithmetic_Echo_0", Arithmetic_Echo_0());
-    tests.put("Arithmetic_Echo_1", Arithmetic_Echo_1());
-    tests.put("Arithmetic_Echo_2", Arithmetic_Echo_2());
-    tests.put("Arithmetic_Echo_3", Arithmetic_Echo_3());
-    tests.put("Arithmetic_Echo_4", Arithmetic_Echo_4());
-
-    TestBench.runTests(tests);
-  }
-
-  public static boolean Arithmetic_Echo_0() {
-    // Simple smoke test
-    try {
-      String input = "3 + 5";
-      String expectedOutput = "(3 + 5)";
-      String actualOutput = runSyntax(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  public static boolean Arithmetic_Echo_1() {
-    // Test with multiplication
-    try {
-      String input = "2 * 3";
-      String expectedOutput = "(2 * 3)";
-      String actualOutput = runSyntax(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  public static boolean Arithmetic_Echo_2() {
-    // Test with parentheses
-    try {
-      String input = "2 * (3 + 4)";
-      String expectedOutput = "(2 * (3 + 4))";
-      String actualOutput = runSyntax(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  public static boolean Arithmetic_Echo_3() {
-    // Test with division
-    try {
-      String input = "10 / 2";
-      String expectedOutput = "(10 / 2)";
-      String actualOutput = runSyntax(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  public static boolean Arithmetic_Echo_4() {
-    // Test with complex expression
-    try {
-      String input = "3 + 5 * (10 - 4)";
-      String expectedOutput = "(3 + (5 * (10 - 4)))";
-      String actualOutput = runSyntax(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  private static String runSyntax(String input) throws Exception {
-    Lexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
-    CommonTokenStream tokens = new CommonTokenStream(lexer);
-    ArithmeticParser parser = new ArithmeticParser(tokens);
-    Method startRule = parser.getClass().getMethod("program");
-    ParseTree tree = (ParseTree) startRule.invoke(parser);
-
-    Arithmetic_Echo_PrintVisitor visitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
-    return visitor.visit(tree);
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_Swap.java b/developer/javac/primary/Arithmetic_Swap.java
deleted file mode 100644 (file)
index 58e1caf..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Arithmetic_Swap {
-  private static final String USAGE_MESSAGE =
-    "Usage: Arithmetic_Swap [-version] <source-file-path>";
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (String arg : args) {
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if (version) {
-      System.out.println("version 0.1");
-      System.exit(error ? 1 : 0);
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if (error) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String inputFile = argList.get(0);
-    String input = Files.readString(Paths.get(inputFile));
-
-    try {
-      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
-      CommonTokenStream tokens = new CommonTokenStream(lexer);
-      ArithmeticParser parser = new ArithmeticParser(tokens);
-      
-      ParseTree tree = parser.program();
-
-      Arithmetic_SwapVisitor swapVisitor = new Arithmetic_SwapVisitor();
-      ParseTree transformedTree = swapVisitor.visit(tree);
-
-      Arithmetic_Echo_PrintVisitor printVisitor = new Arithmetic_Echo_PrintVisitor(parser.getRuleNames());
-      String output = printVisitor.visit(transformedTree);
-
-      System.out.println(output);
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_SwapVisitor.java b/developer/javac/primary/Arithmetic_SwapVisitor.java
deleted file mode 100644 (file)
index f108735..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-import org.antlr.v4.runtime.tree.*;
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.misc.*;
-
-public class Arithmetic_SwapVisitor extends AbstractParseTreeVisitor<ParseTree> {
-
-    @Override
-    public ParseTree visit(ParseTree tree) {
-        if (tree instanceof ParserRuleContext) {
-            ParserRuleContext ctx = (ParserRuleContext) tree;
-            ParserRuleContext newCtx = new ParserRuleContext();
-
-            // Recursively visit all children and add them to the new context
-            for (int i = 0; i < ctx.getChildCount(); i++) {
-                ParseTree child = ctx.getChild(i);
-                ParseTree visitedChild = this.visit(child);
-                
-                // Add child if it's a valid type
-                if (visitedChild instanceof ParserRuleContext) {
-                    newCtx.addChild((ParserRuleContext) visitedChild);
-                } else if (visitedChild instanceof TerminalNode) {
-                    newCtx.addChild((TerminalNode) visitedChild);
-                }
-            }
-            return newCtx;
-        } else if (tree instanceof TerminalNode) {
-            TerminalNode node = (TerminalNode) tree;
-            // Swap operators based on text
-            switch (node.getText()) {
-                case "+":
-                    return createTerminalNode(node, ArithmeticParser.MINUS); // Swap + with -
-                case "-":
-                    return createTerminalNode(node, ArithmeticParser.PLUS);  // Swap - with +
-                case "*":
-                    return createTerminalNode(node, ArithmeticParser.DIVIDE); // Swap * with /
-                case "/":
-                    return createTerminalNode(node, ArithmeticParser.MULTIPLY); // Swap / with *
-                default:
-                    return node; // Return node as is for non-operator tokens
-            }
-        }
-        return null;
-    }
-
-    // Helper method to create a new TerminalNode with the swapped token
-    private TerminalNode createTerminalNode(TerminalNode oldNode, int newTokenType) {
-        Token newToken = new CommonToken(newTokenType, oldNode.getText());
-        return new TerminalNodeImpl(newToken);
-    }
-}
diff --git a/developer/javac/primary/Arithmetic_SyntaxAnnotate.java b/developer/javac/primary/Arithmetic_SyntaxAnnotate.java
deleted file mode 100644 (file)
index 0516db6..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-Takes an 'Ariethemetic' grammar source file.  Parses it. Outputs an annotated
-version of the source file while labeling what parts of the grammar the syntax
-objects belong to.  Note the -pp option.
-
-*/
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Arithmetic_SyntaxAnnotate {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE = 
-    "Usage: Arithmetic_SyntaxAnnotate [-version] [-pp] <source-file>";
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    boolean pretty_print = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        case "-pp":
-          pretty_print = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String input_file = argList.get(0);
-    String input = Files.readString(Paths.get(input_file));
-
-    try {
-      ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
-      CommonTokenStream tokens = new CommonTokenStream(lexer);
-      ArithmeticParser parser = new ArithmeticParser(tokens);
-      ParseTree tree = parser.program();
-
-      Arithmetic_SyntaxAnnotate_PrintVisitor visitor = 
-        new Arithmetic_SyntaxAnnotate_PrintVisitor(parser.getRuleNames(), pretty_print);
-      String output = visitor.visit(tree);
-      System.out.println(output);
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_SyntaxAnnotate_PrintVisitor.java b/developer/javac/primary/Arithmetic_SyntaxAnnotate_PrintVisitor.java
deleted file mode 100644 (file)
index 9831e54..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
-
-public class Arithmetic_SyntaxAnnotate_PrintVisitor extends ArithmeticBaseVisitor<String>{
-  private final String[] rule_names;
-  private final boolean pretty_print;
-
-  public Arithmetic_SyntaxAnnotate_PrintVisitor(String[] rule_names, boolean pretty_print){
-    this.rule_names = rule_names;
-    this.pretty_print = pretty_print;
-  }
-
-  private String indent(int level){
-    return "  ".repeat(level);
-  }
-
-  @Override
-  public String visitProgram(ArithmeticParser.ProgramContext ctx){
-    if(pretty_print){
-      StringBuilder result = new StringBuilder();
-      result.append("program\n").append(visitExpression(ctx.expression(), 1));
-      return result.toString();
-    }else{
-      return "program(" + visit(ctx.expression()) + ")";
-    }
-  }
-
-  @Override
-  public String visitExpression(ArithmeticParser.ExpressionContext ctx){
-    return visitExpression(ctx, 0);
-  }
-
-  private String visitExpression(ArithmeticParser.ExpressionContext ctx, int indent_level){
-    StringBuilder result = new StringBuilder();
-    if(pretty_print){
-      result.append(indent(indent_level)).append("expression(\n");
-      if( ctx.INT() != null ){
-        result.append(indent(indent_level + 1)).append("INT(").append(ctx.INT().getText()).append(")\n");
-      }else if( ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(") ){
-        result.append(indent(indent_level + 1)).append("(\n");
-        result.append(visitExpression(ctx.expression(0), indent_level + 2));
-        result.append(indent(indent_level + 1)).append(")\n");
-      }else{
-        result.append(visitExpression(ctx.expression(0), indent_level + 1));
-        result.append(indent(indent_level + 1)).append("operator(").append(ctx.getChild(1).getText()).append(")\n");
-        result.append(visitExpression(ctx.expression(1), indent_level + 1));
-      }
-      result.append(indent(indent_level)).append(")\n");
-    }else{
-      if( ctx.INT() != null ){
-        result.append("INT(").append(ctx.INT().getText()).append(")");
-      }else if( ctx.getChildCount() == 3 && ctx.getChild(0).getText().equals("(") ){
-        result.append("(").append(visit(ctx.expression(0))).append(")");
-      }else{
-        String left = visit(ctx.expression(0));
-        String right = visit(ctx.expression(1));
-        String operator = "operator(" + ctx.getChild(1).getText() + ")";
-        result.append("expression(").append(left).append(" ").append(operator).append(" ").append(right).append(")");
-      }
-    }
-    return result.toString();
-  }
-}
diff --git a/developer/javac/primary/Arithmetic_SyntaxAnnotate__Test.java b/developer/javac/primary/Arithmetic_SyntaxAnnotate__Test.java
deleted file mode 100644 (file)
index a80b690..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Arithmetic_SyntaxAnnotate__Test {
-
-  public static boolean Arithmetic_SyntaxAnnotate_0() {
-    return runTest(
-      "Arithmetic_SyntaxAnnotate__Test_0.txt"
-     ,"program(expression(INT(3) operator(+) INT(5)))"
-     );
-  }
-
-  public static boolean Arithmetic_SyntaxAnnotate_1() {
-    return runTest(
-      "Arithmetic_SyntaxAnnotate__Test_1.txt"
-      ,"program(expression(INT(3) operator(+) INT(5)))"
-   );
-  }
-
-  public static boolean Arithmetic_SyntaxAnnotate_2() {
-    return runTest(
-      "Arithmetic_SyntaxAnnotate__Test_2.txt" 
-      ,"program(expression(INT(2) operator(*) (expression(INT(3) operator(+) INT(4)))))"
-      );
-  }
-
-  public static boolean Arithmetic_SyntaxAnnotate_3() {
-    return runTest(
-      "Arithmetic_SyntaxAnnotate__Test_3.txt" 
-      ,"program(expression(INT(10) operator(/) INT(2)))"
-      );
-  }
-
-  public static boolean Arithmetic_SyntaxAnnotate_4() {
-    return runTest(
-      "Arithmetic_SyntaxAnnotate__Test_4.txt" 
-      ,"program(expression(INT(3) operator(+) expression(INT(5) operator(*) (expression(INT(10) operator(-) INT(4))))))"
-      );
-  }
-
-  private static boolean runTest(String filename ,String expectedOutput) {
-    try {
-      String input = Files.readString(Paths.get(filename));
-      String actualOutput = runSyntaxAnnotate(input);
-      return expectedOutput.equals(actualOutput);
-    } catch (Exception e) {
-      e.printStackTrace();
-      return false;
-    }
-  }
-
-  private static String runSyntaxAnnotate(String input) throws Exception {
-    Lexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
-    CommonTokenStream tokens = new CommonTokenStream(lexer);
-    ArithmeticParser parser = new ArithmeticParser(tokens);
-    ParseTree tree = parser.program(); // Directly calling the start rule method
-
-    Arithmetic_SyntaxAnnotate_PrintVisitor visitor = new Arithmetic_SyntaxAnnotate_PrintVisitor(parser.getRuleNames() ,false);
-    return visitor.visit(tree);
-  }
-
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE = 
-    "Usage: Arithmetic_SyntaxAnnotate__Test [-version]";
-
-  public static void main(String[] args) {
-    // if (args.length == 0) {
-    //   System.err.println(USAGE_MESSAGE);
-    //   System.exit(1);
-    // }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 0) {
-      System.err.println("This program takes no arguments.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    // Use LinkedHashMap to maintain order of test results
-    Map<String, Boolean> tests = new LinkedHashMap<>();
-    tests.put("Arithmetic_SyntaxAnnotate_0", Arithmetic_SyntaxAnnotate_0());
-    tests.put("Arithmetic_SyntaxAnnotate_1", Arithmetic_SyntaxAnnotate_1());
-    tests.put("Arithmetic_SyntaxAnnotate_2", Arithmetic_SyntaxAnnotate_2());
-    tests.put("Arithmetic_SyntaxAnnotate_3", Arithmetic_SyntaxAnnotate_3());
-    tests.put("Arithmetic_SyntaxAnnotate_4", Arithmetic_SyntaxAnnotate_4());
-
-    TestBench.runTests(tests);
-  }
-
-}
-
diff --git a/developer/javac/primary/RuleNameList.java b/developer/javac/primary/RuleNameList.java
deleted file mode 100644 (file)
index c9b727c..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-  Accepts an grammar name (not a file path or file name) and outputs the rule
-  names found in the grammar.  
-
-  RuleNameList does not run antlr to build the grammar files, that must have
-  been done separately before this program is run.
-
-  RuleNameList produces a more reliable list than does RuleNameListRegx.
-
-  RuleNameList does not output terminal symbols (the lexer tokens).
-
-  Usage: ANTLRv4_RuleNames <input-file>
-*/
-
-import org.antlr.v4.runtime.*;
-import java.util.ArrayList;
-import java.util.List;
-
-public class RuleNameList {
-
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE =
-    "Usage: RuleNameList"
-    +" [-version]"
-    +" [-rule (default)] [-no-rule]"
-    +" [-token] [-no-token (default)]"
-    +" <grammar-name>"
-    ;
-
-  public static void main(String[] args) {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    boolean printRules = true;
-    boolean printTokens = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        case "-rule":
-          printRules = true;
-          break;
-        case "-no-rule":
-          printRules = false;
-          break;
-        case "-token":
-          printTokens = true;
-          break;
-        case "-no-token":
-          printTokens = false;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String grammarName = argList.get(0);
-    // in case the user provided a path instead of a name:
-    grammarName = Paths.get(grammarName).getFileName().toString().replace(".g4", "");
-
-    try {
-      // Dynamically load the appropriate lexer and parser
-      Class<?> lexerClass = Class.forName(grammarName + "Lexer");
-      Class<?> parserClass = Class.forName(grammarName + "Parser");
-
-      // Create instances of the lexer and parser
-      Lexer lexer = (Lexer) lexerClass.getConstructor(CharStream.class).newInstance(CharStreams.fromString(""));
-      CommonTokenStream tokens = new CommonTokenStream(lexer);
-      Parser parser = (Parser) parserClass.getConstructor(TokenStream.class).newInstance(tokens);
-
-      // Get the rule names from the parser
-      List<String> ruleNames = List.of(parser.getRuleNames());
-
-      // Get the token names from the lexer
-      List<String> tokenNames = List.of(lexer.getTokenNames());
-
-      // Print the rule names if requested
-      if (printRules) {
-        if (printTokens) {
-          System.out.println("#----------------------------------------");
-          System.out.println("# Rule names found in the grammar:");
-        }
-        for (String ruleName : ruleNames) {
-          System.out.println(ruleName);
-        }
-      }
-
-      // Print the token names if requested
-      if (printTokens) {
-        if (printRules) {
-          System.out.println("#----------------------------------------");
-          System.out.println("# Token names found in the grammar:");
-        }
-        for (String tokenName : tokenNames) {
-          System.out.println(tokenName);
-        }
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/developer/javac/primary/RuleNameListRegx.java b/developer/javac/primary/RuleNameListRegx.java
deleted file mode 100644 (file)
index 36ffb2b..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-Directly reads an ANTLR grammar file, a `.g4` file, and lists all the rules found in it.
-
-*/
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.ArrayList;
-import java.util.List;
-
-public class RuleNameListRegx {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE =
-    "Usage: RuleNameListRegx [-version] <path-to-g4-file>";
-
-  public static void main(String[] args) {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    boolean pretty_print = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        case "-pp":
-          pretty_print = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }
-    }
-    if (argList.size() != 1) {
-      System.err.println("Expected exactly one non-option argument.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String filePath = argList.get(0);
-
-    try {
-      Set<String> ruleNames = new HashSet<>();
-      BufferedReader br = new BufferedReader(new FileReader(filePath));
-      StringBuilder content = new StringBuilder();
-      String line;
-      while ((line = br.readLine()) != null) {
-        content.append(line).append("\n");
-      }
-
-      // Updated pattern to handle multi-line rules
-      Pattern rulePattern = Pattern.compile("(?m)^\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*:");
-
-      Matcher matcher = rulePattern.matcher(content.toString());
-      while (matcher.find()) {
-        ruleNames.add(matcher.group(1));
-      }
-
-      System.out.println("Extracted Rules:");
-      for (String rule : ruleNames) {
-        System.out.println(rule);
-      }
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-  }
-}
diff --git a/developer/javac/primary/StringUtils.java b/developer/javac/primary/StringUtils.java
deleted file mode 100644 (file)
index 774e253..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-public class StringUtils {
-
-    private static int spacesPerIndentLevel = 2; // Default to 2 spaces per indent level
-
-    public static void setSpacesPerIndentLevel(int spaces) {
-        spacesPerIndentLevel = spaces;
-    }
-
-    public static String indentString(String template, int indentLevel) {
-        String indent = " ".repeat(spacesPerIndentLevel * indentLevel);
-        String[] lines = template.split("\n");
-        StringBuilder indentedTemplate = new StringBuilder();
-        for (String line : lines) {
-            indentedTemplate.append(indent).append(line).append("\n");
-        }
-        return indentedTemplate.toString();
-    }
-}
diff --git a/developer/javac/primary/Synthesize_SyntaxAnnotate.java b/developer/javac/primary/Synthesize_SyntaxAnnotate.java
deleted file mode 100644 (file)
index 6f002f1..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-
-public class Synthesize_SyntaxAnnotate {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE = 
-    "Usage: Synthesize_SyntaxAnnotate [-version] <grammar-name> <output-file-path>";
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 2) {
-      System.err.println("Expected exactly two non-option arguments.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String grammarName = argList.get(0);
-    // in case the user provided a path instead of a name:
-    grammarName = Paths.get(grammarName).getFileName().toString().replace(".g4", "");
-
-    String outputFile = argList.get(1);
-
-    synthesizeSyntaxAnnotateClass(grammarName, outputFile);
-  }
-
-  private static void synthesizeSyntaxAnnotateClass(String grammarName, String outputFile) throws IOException {
-    String className = grammarName + "_SyntaxAnnotate";
-    String lexerName = grammarName + "Lexer";
-    String parserName = grammarName + "Parser";
-    String visitorName = grammarName + "_SyntaxAnnotate_PrintVisitor";
-
-    // Template for the SyntaxAnnotate class
-    String classTemplate = """
-      /* This file generated by Synthesize_SyntaxAnnotate given the grammar 
-         name: ____4_.
-         
-         SyntaxAnnotate programs accept a source file, then echo the source file with
-         syntax annotation. Synthesize_SyntaxAnnotate produces a SyntaxAnnotate program
-         for a specific grammar.
-       */
-      import org.antlr.v4.runtime.*;
-      import org.antlr.v4.runtime.tree.*;
-      import java.io.IOException;
-      import java.nio.file.Files;
-      import java.nio.file.Paths;
-      import java.util.ArrayList;
-      import java.util.List;
-
-      public class ____0_ {
-        // Constant for the usage message
-        private static final String USAGE_MESSAGE =
-          "Usage: ____0_ [-version] [-pp] <source-file-path>";
-
-        public static void main(String[] args) throws IOException {
-          if (args.length == 0) {
-            System.err.println(USAGE_MESSAGE);
-            System.exit(1);
-          }
-          boolean error = false;
-          boolean version = false;
-          boolean pretty_print = false;
-          List<String> argList = new ArrayList<>();
-          for (int i = 0; i < args.length; i++) {
-            String arg = args[i];
-            if (arg.startsWith("-")) {
-              switch (arg) {
-              case "-version":
-                version = true;
-                break;
-              case "-pp":
-                pretty_print = true;
-                break;
-              default:
-                System.err.println("Unrecognized option: " + arg);
-                error = true;
-              }
-            } else {
-              argList.add(arg);
-            }
-          }
-          if(version){
-            System.out.println("version 0.1");
-            if(error){
-              System.exit(1);
-            }else{
-              System.exit(0);
-            }        
-          }
-          if (argList.size() != 1) {
-            System.err.println("Expected exactly one non-option argument.");
-            error = true;
-          }
-          if(error){
-            System.err.println(USAGE_MESSAGE);
-            System.exit(1);
-          }
-
-          String input_file = argList.get(0);
-          String input = Files.readString(Paths.get(input_file));
-
-          try {
-            ____1_ lexer = new ____1_(CharStreams.fromString(input));
-            CommonTokenStream tokens = new CommonTokenStream(lexer);
-            ____2_ parser = new ____2_(tokens);
-            ParseTree tree = parser.program();
-
-            ____3_ visitor = new ____3_(parser.getRuleNames(), pretty_print);
-            String output = visitor.visit(tree);
-            System.out.println(output);
-          } catch (Exception e) {
-            e.printStackTrace();
-          }
-        }
-      }
-      """;
-
-    // Fill in the blanks in the template
-    classTemplate = classTemplate.replace("____0_", className);
-    classTemplate = classTemplate.replace("____1_", lexerName);
-    classTemplate = classTemplate.replace("____2_", parserName);
-    classTemplate = classTemplate.replace("____3_", visitorName);
-    classTemplate = classTemplate.replace("____4_", grammarName);
-
-    // Write the synthesized class to the output file
-    Files.writeString(Paths.get(outputFile), classTemplate);
-  }
-}
-
-//  LocalWords:  SyntaxAnnotate
diff --git a/developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitor.java b/developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitor.java
deleted file mode 100644 (file)
index ae508b0..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-import org.antlr.v4.runtime.*;
-import org.antlr.v4.runtime.tree.*;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-import java.io.PrintWriter;
-
-public class Synthesize_SyntaxAnnotate_PrintVisitor {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE = 
-    "Usage: Synthesize_SyntaxAnnotate_PrintVisitor"
-    +" [-version]"
-    +" <g4-grammar-file-path> <outputFile> [indent-level (default 0)]"
-    ;
-
-  public static void main(String[] args) throws IOException {
-  if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    int indentLevel = 0;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if (version) {
-      System.out.println("Version 0.1");
-      if (error) {
-        System.exit(1);
-      } else {
-        System.exit(0);
-      }
-    }
-    if (argList.size() < 2 || argList.size() > 3) {
-      System.err.println("Expected two or three non-option arguments.");
-      error = true;
-    }
-    if (error) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String grammarFilePath = argList.get(0);
-    String outputFile      = argList.get(1);
-    if (argList.size() == 3) {
-      indentLevel = Integer.parseInt(argList.get(2));
-    }
-
-    String grammarName = Paths.get(grammarFilePath).getFileName().toString().replace(".g4", "");
-    String parserName = grammarName + "Parser";
-    String visitorClassName = grammarName + "_SyntaxAnnotate_PrintVisitor";
-
-    // Parse the .g4 file
-    CharStream input = CharStreams.fromFileName(grammarFilePath);
-    ANTLRv4Lexer lexer = new ANTLRv4Lexer(input);
-    CommonTokenStream tokens = new CommonTokenStream(lexer);
-    ANTLRv4Parser parser = new ANTLRv4Parser(tokens);
-
-    // Extract rules
-    ParseTree tree = parser.grammarSpec();
-    List<String> ruleNames = extractRuleNames(parser);
-
-    // Synthesize the print methods
-    StringBuilder printMethods = new StringBuilder();
-    for (String ruleName : ruleNames) {
-      printMethods.append(Synthesize_SyntaxAnnotate_PrintVisitorMethod.synthesizePrintMethod(parserName, ruleName, indentLevel + 1));
-    }
-
-    // Template for the PrintVisitor class
-    String classTemplate = """
-      /* This file synthesized by Synthesize_SyntaxAnnotate_PrintVisitor.
-      */
-      import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
-
-      public class ____0_ extends AbstractParseTreeVisitor<String> {
-        private final String[] ruleNames;
-
-        public ____0_(String[] ruleNames) {
-          this.ruleNames = ruleNames;
-        }
-
-        ____1_
-      }
-      """;
-
-    classTemplate = classTemplate.replace("____0_", visitorClassName);
-    classTemplate = classTemplate.replace("____1_", printMethods.toString());
-
-    try (PrintWriter writer = new PrintWriter(outputFile)) {
-      writer.print(classTemplate);
-    }
-  }
-
-  private static List<String> extractRuleNames(Parser parser) {
-    // Extract rule names from the parser
-    return Arrays.asList(parser.getRuleNames());
-  }
-}
-
-//  LocalWords:  SyntaxAnnotate PrintVisitor
diff --git a/developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java b/developer/javac/primary/Synthesize_SyntaxAnnotate_PrintVisitorMethod.java
deleted file mode 100644 (file)
index 35394bb..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-import java.util.ArrayList;
-import java.util.List;
-import java.io.PrintWriter;
-
-public class Synthesize_SyntaxAnnotate_PrintVisitorMethod {
-  // Constant for the usage message
-  private static final String USAGE_MESSAGE = 
-    "Usage: Synthesize_SyntaxAnnotate_PrintVisitorMethod"
-    + " [-version]"
-    +" <grammar-name> <g4-rule-name> <output-file>"
-    ;
-
-  public static void main(String[] args) {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-    boolean error = false;
-    boolean version = false;
-    List<String> argList = new ArrayList<>();
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (arg.startsWith("-")) {
-        switch (arg) {
-        case "-version":
-          version = true;
-          break;
-        default:
-          System.err.println("Unrecognized option: " + arg);
-          error = true;
-        }
-      } else {
-        argList.add(arg);
-      }
-    }
-    if(version){
-      System.out.println("version 0.1");
-      if(error){
-        System.exit(1);
-      }else{
-        System.exit(0);
-      }        
-    }
-    if (argList.size() != 3) {
-      System.err.println("Expected exactly three non-option arguments.");
-      error = true;
-    }
-    if(error){
-      System.err.println(USAGE_MESSAGE);
-      System.exit(1);
-    }
-
-    String grammarName = argList.get(0);
-    String ruleName    = argList.get(1);
-    String outputFile  = argList.get(2);
-
-    String parserName = grammarName + "Parser";
-    
-    try {
-      PrintWriter writer = new PrintWriter(outputFile);
-      // start at indent level 0
-      writer.print(synthesizePrintMethod(parserName, ruleName, 0)); 
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-
-  public static String synthesizePrintMethod(String parserName, String ruleName, int indentLevel) {
-    // Template for the print method using text blocks
-    String template = """
-      public String visit____0_ (____1_.____0_Context ctx) {
-        StringBuilder result = new StringBuilder();
-        result.append("____0_(");
-        for (int i = 0; i < ctx.getChildCount(); i++) {
-          if (i > 0) result.append(", ");
-          result.append(visit(ctx.getChild(i)));
-        }
-        result.append(")");
-        return result.toString();
-      }
-      """;
-
-    // Fill in the blanks in the template
-    template = template.replace("____0_", ruleName);
-    template = template.replace("____1_", parserName);
-
-    // Indent the template
-    return StringUtils.indentString(template, indentLevel);
-  }
-}
diff --git a/developer/javac/primary/TestBench.java b/developer/javac/primary/TestBench.java
deleted file mode 100644 (file)
index 8bdcc67..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-import java.util.Map;
-
-public class TestBench {
-
-    public static void runTests(Map<String, Boolean> tests) {
-        int totalTests = tests.size();
-        int passedTests = 0;
-        int failedTests = 0;
-
-        for (Map.Entry<String, Boolean> test : tests.entrySet()) {
-            try {
-                if (test.getValue()) {
-                    passedTests++;
-                } else {
-                    System.out.println("failed: " + test.getKey());
-                    failedTests++;
-                }
-            } catch (Exception e) {
-                System.out.println("failed: " + test.getKey());
-                failedTests++;
-            }
-        }
-
-        System.out.println("Total tests run: " + totalTests);
-        System.out.println("Total tests passed: " + passedTests);
-        System.out.println("Total tests failed: " + failedTests);
-    }
-}
diff --git a/developer/ologist/.ispell_antlr b/developer/ologist/.ispell_antlr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/developer/ologist/cycle_dection.html b/developer/ologist/cycle_dection.html
new file mode 100644 (file)
index 0000000..3c9fb85
--- /dev/null
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Dependency Build Algorithm</title>
+  <style>
+    body {
+      background-color: hsl(0, 0%, 0%); /* Black background */
+      color: hsl(40, 100%, 85%); /* Wheatgrass color (offwhite with a tan hue) */
+      font-family: "Courier New", Courier, monospace;
+    }
+    code {
+      background-color: hsl(0, 0%, 15%); /* Dark gray background for code blocks */
+      border: 1px solid hsl(0, 0%, 25%); /* Slightly lighter gray for the border */
+      border-radius: 4px;
+      padding: 4px;
+      color: hsl(40, 100%, 85%); /* Wheatgrass-colored text */
+      display: inline-block; /* Inline-block to extend only as long as the code */
+      white-space: pre-wrap;
+      font-size: 14px;
+    }
+    ol {
+      margin-left: 20px;
+    }
+    li {
+      margin-bottom: 10px;
+    }
+    h1, h2 {
+      color: hsl(40, 100%, 75%); /* Lighter wheatgrass color for headers */
+    }
+    a {
+      color: hsl(150, 100%, 65%); /* Light green for links */
+    }
+  </style>
+</head>
+<body>
+  <h2>Cycle Detection in Dependency Graph</h2>
+  <h3>Overview</h3>
+  <p>
+    The <code>is_acyclic_q</code> function is designed to detect cycles in a dependency graph using a depth-first search (DFS) algorithm. It starts from a list of root node labels and traverses the graph to ensure that there are no cycles. If a cycle is detected, the function marks the nodes involved and continues to explore other parts of the graph.
+  </p>
+  <h3>Key Concepts</h3>
+  <ul>
+    <li><strong>Dependency Graph</strong>: A graph where nodes represent build targets and edges represent dependencies between these targets.</li>
+    <li><strong>Depth-First Search (DFS)</strong>: An algorithm for traversing or searching tree or graph data structures. It starts at the root and explores as far as possible along each branch before backtracking.</li>
+    <li><strong>Cycle Detection</strong>: The process of identifying cycles (loops) in a graph, where a cycle is a path that starts and ends at the same node.</li>
+  </ul>
+  <h3>Functions</h3>
+  <h4>1. is_acyclic_q</h4>
+  <p>
+    <strong>Purpose</strong>: To determine if the dependency graph is acyclic (i.e., contains no cycles).
+  </p>
+  <p>
+    <strong>Parameters</strong>: 
+    <ul>
+      <li><code>root_node_labels</code>: A list of labels for the root nodes to start the cycle search.</li>
+      <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Returns</strong>: 
+    <ul>
+      <li><code>'acyclic'</code> if no cycles are found.</li>
+      <li><code>'cycle_found'</code> if cycles are detected.</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Process</strong>:
+    <ul>
+      <li>Initializes a stack for DFS traversal.</li>
+      <li>Iteratively calls the <code>is_acyclic_q_descend</code> function to traverse the graph and detect cycles.</li>
+      <li>Updates the traversal state and continues exploring other paths until the stack is empty.</li>
+    </ul>
+  </p>
+  <h4>2. is_acyclic_q_descend</h4>
+  <p>
+    <strong>Purpose</strong>: To perform the actual DFS traversal and cycle detection for a given path.
+  </p>
+  <p>
+    <strong>Parameters</strong>: 
+    <ul>
+      <li><code>path_stack</code>: A stack representing the current path in the graph.</li>
+      <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Returns</strong>: 
+    <ul>
+      <li><code>'leaf_node'</code> if the current node has no children.</li>
+      <li><code>'cycle_found'</code> if a cycle is detected.</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Process</strong>:
+    <ul>
+      <li>Collects the current path and node.</li>
+      <li>Checks for cycles by comparing the current node with nodes in the path.</li>
+      <li>Marks nodes involved in cycles and updates the stack to continue traversal.</li>
+    </ul>
+  </p>
+  <h3>Usage</h3>
+  <p>
+    The <code>is_acyclic_q</code> function is used to ensure that the dependency graph defined in the build file is free of cycles. This is crucial for preventing infinite loops and ensuring that the build process can proceed smoothly.
+  </p>
+</body>
+</html>
diff --git a/developer/ologist/dependency_graph.html b/developer/ologist/dependency_graph.html
new file mode 100644 (file)
index 0000000..378c52d
--- /dev/null
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Dependency Build Algorithm</title>
+  <style>
+    body {
+      background-color: hsl(0, 0%, 0%); /* Black background */
+      color: hsl(40, 100%, 85%); /* Wheatgrass color (offwhite with a tan hue) */
+      font-family: "Courier New", Courier, monospace;
+    }
+    code {
+      background-color: hsl(0, 0%, 15%); /* Dark gray background for code blocks */
+      border: 1px solid hsl(0, 0%, 25%); /* Slightly lighter gray for the border */
+      border-radius: 4px;
+      padding: 4px;
+      color: hsl(40, 100%, 85%); /* Wheatgrass-colored text */
+      display: block;
+      white-space: pre-wrap;
+      font-size: 14px;
+    }
+    ol {
+      margin-left: 20px;
+    }
+    li {
+      margin-bottom: 10px;
+    }
+    h1, h2 {
+      color: hsl(40, 100%, 75%); /* Lighter wheatgrass color for headers */
+    }
+    a {
+      color: hsl(150, 100%, 65%); /* Light green for links */
+    }
+  </style>
+</head>
+<body>
+  <h2>Cycle Detection in Dependency Graph</h2>
+  <h3>Overview</h3>
+  <p>
+    The <code>is_acyclic_q</code> function is designed to detect cycles in a dependency graph using a depth-first search (DFS) algorithm. It starts from a list of root node labels and traverses the graph to ensure that there are no cycles. If a cycle is detected, the function marks the nodes involved and continues to explore other parts of the graph.
+  </p>
+  <h3>Key Concepts</h3>
+  <ul>
+    <li><strong>Dependency Graph</strong>: A graph where nodes represent build targets and edges represent dependencies between these targets.</li>
+    <li><strong>Depth-First Search (DFS)</strong>: An algorithm for traversing or searching tree or graph data structures. It starts at the root and explores as far as possible along each branch before backtracking.</li>
+    <li><strong>Cycle Detection</strong>: The process of identifying cycles (loops) in a graph, where a cycle is a path that starts and ends at the same node.</li>
+  </ul>
+  <h3>Functions</h3>
+  <h4>1. is_acyclic_q</h4>
+  <p>
+    <strong>Purpose</strong>: To determine if the dependency graph is acyclic (i.e., contains no cycles).
+  </p>
+  <p>
+    <strong>Parameters</strong>: 
+    <ul>
+      <li><code>root_node_labels</code>: A list of labels for the root nodes to start the cycle search.</li>
+      <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Returns</strong>: 
+    <ul>
+      <li><code>'acyclic'</code> if no cycles are found.</li>
+      <li><code>'cycle_found'</code> if cycles are detected.</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Process</strong>:
+    <ul>
+      <li>Initializes a stack for DFS traversal.</li>
+      <li>Iteratively calls the <code>is_acyclic_q_descend</code> function to traverse the graph and detect cycles.</li>
+      <li>Updates the traversal state and continues exploring other paths until the stack is empty.</li>
+    </ul>
+  </p>
+  <h4>2. is_acyclic_q_descend</h4>
+  <p>
+    <strong>Purpose</strong>: To perform the actual DFS traversal and cycle detection for a given path.
+  </p>
+  <p>
+    <strong>Parameters</strong>: 
+    <ul>
+      <li><code>path_stack</code>: A stack representing the current path in the graph.</li>
+      <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Returns</strong>: 
+    <ul>
+      <li><code>'leaf_node'</code> if the current node has no children.</li>
+      <li><code>'cycle_found'</code> if a cycle is detected.</li>
+    </ul>
+  </p>
+  <p>
+    <strong>Process</strong>:
+    <ul>
+      <li>Collects the current path and node.</li>
+      <li>Checks for cycles by comparing the current node with nodes in the path.</li>
+      <li>Marks nodes involved in cycles and updates the stack to continue traversal.</li>
+    </ul>
+  </p>
+  <h3>Usage</h3>
+  <p>
+    The <code>is_acyclic_q</code> function is used to ensure that the dependency graph defined in the build file is free of cycles. This is crucial for preventing infinite loops and ensuring that the build process can proceed smoothly.
+  </p>
+
+</body>
+</html>  
+
+<h2>2. Run Build Scripts</h2>
+<ol>
+  <li>Traverse the queue starting from the tail (the most recently added nodes).</li>
+  <li>For each node, attempt to build it by checking the file dates of the target node and its dependencies:
+    <ol>
+      <li>If the target file is older than any dependency, execute the node’s build function.</li>
+      <li>After building, recheck the file dates. If the file date has been updated, mark the node as successfully built.</li>
+      <li>If the build fails or the file date is not updated, mark the node with an error in its property list.</li>
+    </ol>
+  </li>
+  <li>Nodes with dependencies marked with errors will not be built, and errors will propagate up the dependency tree.</li>
+</ol>
+
+<h2>3. Final Reporting and Status</h2>
+<ol>
+  <li>If the root node is successfully built, report the success and any other successfully built nodes.</li>
+  <li>If an error has propagated to the root, report the failure.</li>
+  <li>Keep a list of all successfully built nodes and provide a final summary of the build status.</li>
+</ol>
+
+<h2>4. Node Definitions</h2>
+<p>Each node in the dependency graph is defined by a property dictionary. A node is either a symbol or a path:</p>
+<ol>
+  <li>Symbol Nodes: These represent abstract concepts or commands and always trigger a build unless marked with an error.</li>
+  <li>Path Nodes: These represent file paths. A path node is considered built if its target file is newer than its dependencies.</li>
+</ol>
+<p>Both node types are identified by a label, and their dependencies are stored as a list of node labels. The presence of an error property indicates that the node has failed to build or encountered a problem during processing.</p>
+
+</body>
+</html>
diff --git a/developer/ologist/deps.gradle b/developer/ologist/deps.gradle
new file mode 100644 (file)
index 0000000..8427e1f
--- /dev/null
@@ -0,0 +1,240 @@
+// useful regular expressions
+def base = "[a-zA-Z0-9_-]+"
+def ext = "[a-zA-Z0-9_-]+$"
+def name = "${filebase}\.${fileext}"
+def path = "[.]+/${name}"
+
+
+// Predefined returnable functions for comparison
+def no_match_f = { target ->
+    println "No match found for target: ${target}"
+}
+
+def dependency_list_f = { jarFilePath, javaFilePath ->
+    println "Building JAR file for target: ${jarFilePath}"
+    println "Target: ${jarFilePath} depends on: ${javaFilePath}"
+    return [jarFilePath, javaFilePath]
+}
+
+// Main function to handle target matching
+def target_executor(token) {
+    // Match against the expected executor path pattern
+    def match = token =~ /(?:^executor\/)(${base})\.class$/
+
+    // If there’s no match, return the no_match function
+    if (!match) {
+        return no_match_f.curry(token)
+    }
+
+    // Extract the base name of the matched target (e.g., "RuleNameListRegx")
+    def targetBase = match[0][1]
+
+    // Define the expected Java and JAR file paths
+    def javaFilePath = "${javaCompInDir}${targetBase}.java"
+    def jarFilePath = "${executorDir}${targetBase}.jar"
+
+    // Check if the corresponding Java file exists in the javac directory
+    def javaFile = new File(javaFilePath)
+    if (!javaFile.exists()) {
+        // Return the function to print the missing Java file message
+        return no_java_file_f.curry(javaFilePath)
+    }
+
+    // Return the function that handles the JAR build step
+    return build_jar_f.curry(jarFilePath, javaFilePath)
+}
+
+// Example usage:
+def f = target_executor("executor/RuleNameListRegx.class")
+if (f == no_match_f) {
+    println "No match found"
+} else if (f == no_java_file_f) {
+    println "No corresponding Java file"
+} else {
+    f()  // Call the returned function to perform the build
+}
+
+
+
+
+// useful regular expressions
+def base = "[a-zA-Z0-9_-]+"
+def ext = "[a-zA-Z0-9_-]+$"
+def name = "${filebase}\.${fileext}
+def path = "[.]+/${name}"
+
+def target_executor( token ){
+
+  // "(?:" ... ) matches are thrown away
+  def match = token =~ /(?:^executor/)(${base})(?:${ext})/
+
+  // if there is a corresponding primary javac/primary/%1.java file,
+  // then creating the executable wrapper depends upon the .jar
+  // file, which will later chain back to the java file.
+
+  ...
+
+// returns a function that produces the jar file, or returns
+// a function that, if invoked prints the message that there is
+// no corresponding java file.
+
+
+  return ...
+
+}
+
+
+// Define the build target, dependencies, and functions as triples
+def build_triples = [
+  [
+    targets: [""]
+    deps: ["jvm/%1.class"]
+  ]
+
+  ,[ 
+    targets: ["(?:${path}/)
+   ...
+
+  ],
+]
+
+
+
+
+def programMap = [
+  [target: ["exectutor/
+
+    // RuleNameListRegx does not require ANTLR or external tools
+    "RuleNameListRegx": [
+        "wrapped_jar_from_java": "RuleNameListRegx",
+        "java_depends": [],
+        "grammar": [],
+        "program_deps": []
+    ],
+
+    // RuleNameList does not require ANTLR or external tools
+    "RuleNameList": [
+        "wrapped_jar_from_java": "RuleNameList",
+        "java_depends": [],
+        "grammar": [],
+        "program_deps": []
+    ],
+
+    // Synthesize_SyntaxAnnotate_PrintVisitorMethod has dependencies on Java classes
+    "Synthesize_SyntaxAnnotate_PrintVisitorMethod": [
+        "wrapped_jar_from_java": "Synthesize_SyntaxAnnotate_PrintVisitorMethod",
+        "java_depends": ["StringUtils"],
+        "grammar": [],
+        "program_deps": []
+    ],
+
+    // Synthesize_SyntaxAnnotate_PrintVisitor depends on Synthesize_SyntaxAnnotate_PrintVisitorMethod
+    "Synthesize_SyntaxAnnotate_PrintVisitor": [
+        "wrapped_jar_from_java": "Synthesize_SyntaxAnnotate_PrintVisitor",
+        "java_depends": ["StringUtils", "Synthesize_SyntaxAnnotate_PrintVisitorMethod"],
+        "grammar": [],
+        "program_deps": []
+    ],
+
+    // ANTLRv4_RuleNameList requires the ANTLRv4 grammar and is used in parsing ANTLR grammars
+    "ANTLRv4_RuleNameList": [
+        "wrapped_jar_from_java": "ANTLRv4_RuleNameList",
+        "java_depends": [],
+        "grammar": ["ANTLRv4"],
+        "program_deps": []
+    ],
+
+    // Arithmetic_Echo requires the Arithmetic grammar and ANTLR-generated files
+    "Arithmetic_Echo": [
+        "wrapped_jar_from_java": "Arithmetic_Echo",
+        "java_depends": ["Arithmetic_Echo_PrintVisitor"],
+        "grammar": ["Arithmetic"],
+        "program_deps": []
+    ],
+
+    // Arithmetic_Echo__Test also depends on the Arithmetic grammar
+    "Arithmetic_Echo__Test": [
+        "wrapped_jar_from_java": "Arithmetic_Echo__Test",
+        "java_depends": ["Arithmetic_Echo_PrintVisitor"],
+        "grammar": ["Arithmetic"],
+        "program_deps": []
+    ],
+
+    // Arithmetic_SyntaxAnnotate has dependencies on Arithmetic and generated files
+    "Arithmetic_SyntaxAnnotate": [
+        "wrapped_jar_from_java": "Arithmetic_SyntaxAnnotate",
+        "java_depends": ["Arithmetic_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["Arithmetic"],
+        "program_deps": []
+    ],
+
+    // Arithmetic_SyntaxAnnotate__Test has similar dependencies as Arithmetic_SyntaxAnnotate
+    "Arithmetic_SyntaxAnnotate__Test": [
+        "wrapped_jar_from_java": "Arithmetic_SyntaxAnnotate__Test",
+        "java_depends": ["Arithmetic_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["Arithmetic"],
+        "program_deps": []
+    ],
+
+    // Arithmetic2_SyntaxAnnotate has its own grammar and dependencies
+    "Arithmetic2_SyntaxAnnotate": [
+        "wrapped_jar_from_java": "Arithmetic2_SyntaxAnnotate",
+        "java_depends": ["Arithmetic2_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["Arithmetic2"],
+        "program_deps": []
+    ],
+
+    // Arithmetic2_SyntaxAnnotate__Test has the same dependencies as Arithmetic2_SyntaxAnnotate
+    "Arithmetic2_SyntaxAnnotate__Test": [
+        "wrapped_jar_from_java": "Arithmetic2_SyntaxAnnotate__Test",
+        "java_depends": ["Arithmetic2_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["Arithmetic2"],
+        "program_deps": []
+    ],
+
+    // ANTLRv4_SyntaxAnnotate requires the ANTLRv4 grammar
+    "ANTLRv4_SyntaxAnnotate": [
+        "wrapped_jar_from_java": "ANTLRv4_SyntaxAnnotate",
+        "java_depends": ["ANTLRv4_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["ANTLRv4"],
+        "program_deps": []
+    ],
+
+    // Arithmetic_Swap has multiple dependencies on generated files and grammars
+    "Arithmetic_Swap": [
+        "wrapped_jar_from_java": "Arithmetic_Swap",
+        "java_depends": ["Arithmetic_SwapVisitor", "Arithmetic_Echo_PrintVisitor"],
+        "grammar": ["Arithmetic"],
+        "program_deps": []
+    ],
+
+    // GQL-related program with its own grammar and dependencies
+    "GQL_20240412_SyntaxAnnotate": [
+        "wrapped_jar_from_java": "GQL_20240412_SyntaxAnnotate",
+        "java_depends": ["GQL_20240412_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["GQL_20240412"],
+        "program_deps": []
+    ],
+
+    "GQL_20240412_SyntaxAnnotate__Test": [
+        "wrapped_jar_from_java": "GQL_20240412_SyntaxAnnotate__Test",
+        "java_depends": ["GQL_20240412_SyntaxAnnotate_PrintVisitor"],
+        "grammar": ["GQL_20240412"],
+        "program_deps": []
+    ],
+
+    // Additional tools
+    "TerminalToCategory": [
+        "wrapped_jar_from_java": "TerminalToCategory",
+        "java_depends": [],
+        "grammar": [],
+        "program_deps": []
+    ],
+
+    "GrammarSplitter": [
+        "wrapped_jar_from_java": "GrammarSplitter",
+        "java_depends": [],
+        "grammar": [],
+        "program_deps": []
+    ]
+]
index ba4be63..545ab89 100644 (file)
@@ -4,31 +4,10 @@ antlr-mode.el -> .emacs.d
 (autoload 'antlr-mode "antlr-mode" "Major mode for editing ANTLR grammars." t)
 (add-to-list 'auto-mode-alist '("\\.g4\\'" . antlr-mode))
 
-un M-x package-install gradle-mode.
-(require 'gradle-mode)
-(gradle-mode 1)
 
 C-c C-g b to run gradle build
 C-c C-g t to run gradle test
 C-c C-g s to run a single test
 C-c C-g d to run a Gradle command with the daemon
 
-(package-install groovy-mode)
-(require 'groovy-mode)
-(add-to-list 'auto-mode-alist '("\\.gradle\\'" . groovy-mode))
-
-
-;; buffer must be reloaded for it to work
-(package-install 'auto-indent-mode)
-(require 'auto-indent-mode)
-
-(add-hook 'groovy-mode-hook 'auto-indent-mode)
-(add-hook 'groovy-mode-hook
-  (lambda ()
-    (setq tab-width 2)
-    (setq groovy-indent-offset 2)
-    (auto-indent-mode t))) ;; Enable auto-indent-mode
-
-(electric-indent-mode 1)
-(auto-indent-global-mode nil)
-
+e
diff --git a/developer/ologist/groovy.el b/developer/ologist/groovy.el
new file mode 100644 (file)
index 0000000..f08befb
--- /dev/null
@@ -0,0 +1,17 @@
+
+;; Ensure package archives are set up
+(require 'package)
+(setq package-archives '(("melpa" . "https://melpa.org/packages/")
+                         ("gnu" . "https://elpa.gnu.org/packages/")))
+(package-initialize)
+
+;; Install neotree if not already installed
+(unless (package-installed-p 'groovy-mode)
+  (package-refresh-contents)
+  (package-install 'groovy-mode))
+
+;; Configure NeoTree
+(with-eval-after-load 'groovy-mode
+  (setq groovy-indent-offset 2)
+  )
+
index 9f75513..b3fe4d9 100644 (file)
@@ -1,4 +1,4 @@
 
 // settings.gradle
 rootProject.name = 'GQL_to_Cypher'
-
+include "developer"