Skip to content

Instantly share code, notes, and snippets.

@stdray
Last active August 29, 2015 14:12
Show Gist options
  • Select an option

  • Save stdray/60cf7b94fb97116e8df4 to your computer and use it in GitHub Desktop.

Select an option

Save stdray/60cf7b94fb97116e8df4 to your computer and use it in GitHub Desktop.
using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Extensions;
using System;
using SCG = System.Collections.Generic;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace NBox.Data
{
[MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)]
public macro Xsd(namespaceName : string, xsdPath : string)
{
XsdImpl.DoTransform(Macros.ImplicitCTX(), namespaceName, xsdPath)
}
module XsdImpl
{
public DoTransform(typer : Typer, namespaceName : string, xsdPath : string) : void
{
def readXsds(path)
{
def read(path)
{
using(file = File.OpenRead(path))
XmlSchema.Read(file, null)
}
def normalizePath(dir, path)
{
if(Path.IsPathRooted(path)) path
else Path.Combine(dir, path) |> Path.GetFullPath;
}
def paths = SCG.HashSet();
def queue = SCG.Queue([ path ]);
def xsds = SCG.List();
while(queue.Count > 0)
{
def curPath = queue.Dequeue();
when(paths.Add(curPath))
{
def dir = Path.GetDirectoryName(curPath);
def xsd = read(curPath);
xsd.Includes
.OfType.[XmlSchemaExternal]()
.Select(_.SchemaLocation)
.Select(normalizePath(dir, _))
.Iter(queue.Enqueue);
xsds.Add(xsd);
}
}
xsds
}
def buildCodeDom(ns, xsds : Seq[XmlSchema])
{
def xsd = xsds.First();
def schemas = XmlSchemas();
xsds.Iter(s => _ = schemas.Add(s));
schemas.Compile(null, true);
def importer = XmlSchemaImporter(schemas);
def namespce = CodeNamespace(ns);
def exporter = XmlCodeExporter(namespce);
xsd.SchemaTypes.Values
.OfType.[XmlSchemaType]()
.Select(_.QualifiedName)
.Select(importer.ImportSchemaType)
.Iter(exporter.ExportTypeMapping);
xsd.Elements.Values
.OfType.[XmlSchemaElement]()
.Select(_.QualifiedName)
.Select(importer.ImportTypeMapping)
.Iter(exporter.ExportTypeMapping);
CodeGenerator.ValidateIdentifiers(namespce);
namespce
}
def buildSource(dom)
{
def provider = NemerleCodeProvider();
def writer = StringWriter();
provider.GenerateCodeFromNamespace(dom, writer, CodeGeneratorOptions());
writer.ToString()
}
def parseDeclarations(manager, code)
{
def fileName = Path.ChangeExtension(Path.GetTempFileName(), ".n");
File.WriteAllText(fileName, code);
def source = FileSource(fileName, WarningOptions());
manager.Parser.Parse(source).TopDeclarations;
}
def registerDeclarations(env, decls)
{
foreach(d in decls)
_ = env.Define(ClassMember.TypeDeclaration(d))
}
def namespaceParts(namespaceName : string)
{
def parts = namespaceName
.Split(array['.'], StringSplitOptions.RemoveEmptyEntries)
.NToList();
typer.Manager.CoreEnv.EnterIntoNamespace(parts)
}
xsdPath
|> readXsds
|> buildCodeDom(namespaceName, _)
|> buildSource
|> parseDeclarations(typer.Manager, _)
|> registerDeclarations(namespaceParts(namespaceName), _)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment