144 lines
5.2 KiB
C#
144 lines
5.2 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using Microsoft.AspNet.Mvc.Razor.Host;
|
|
using Microsoft.AspNet.Razor.Generator;
|
|
using Microsoft.AspNet.Razor.Parser;
|
|
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
using Microsoft.AspNet.Razor.Text;
|
|
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
|
|
|
|
namespace Microsoft.AspNet.Mvc.Razor
|
|
{
|
|
public class MvcRazorCodeParser : CSharpCodeParser
|
|
{
|
|
private const string ModelKeyword = "model";
|
|
private const string InjectKeyword = "inject";
|
|
private readonly string _baseType;
|
|
private SourceLocation? _endInheritsLocation;
|
|
private bool _modelStatementFound;
|
|
|
|
public MvcRazorCodeParser(string baseType)
|
|
{
|
|
_baseType = baseType;
|
|
MapDirectives(ModelDirective, ModelKeyword);
|
|
MapDirectives(InjectDirective, InjectKeyword);
|
|
}
|
|
|
|
protected override void InheritsDirective()
|
|
{
|
|
// Verify we're on the right keyword and accept
|
|
AssertDirective(SyntaxConstants.CSharp.InheritsKeyword);
|
|
AcceptAndMoveNext();
|
|
_endInheritsLocation = CurrentLocation;
|
|
|
|
InheritsDirectiveCore();
|
|
CheckForInheritsAndModelStatements();
|
|
}
|
|
|
|
private void CheckForInheritsAndModelStatements()
|
|
{
|
|
if (_modelStatementFound && _endInheritsLocation.HasValue)
|
|
{
|
|
Context.OnError(_endInheritsLocation.Value,
|
|
Resources.FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(ModelKeyword));
|
|
}
|
|
}
|
|
|
|
protected virtual void ModelDirective()
|
|
{
|
|
// Verify we're on the right keyword and accept
|
|
AssertDirective(ModelKeyword);
|
|
AcceptAndMoveNext();
|
|
|
|
var endModelLocation = CurrentLocation;
|
|
|
|
BaseTypeDirective(Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(ModelKeyword),
|
|
CreateModelCodeGenerator);
|
|
|
|
if (_modelStatementFound)
|
|
{
|
|
Context.OnError(endModelLocation,
|
|
Resources.FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(ModelKeyword));
|
|
}
|
|
|
|
_modelStatementFound = true;
|
|
|
|
CheckForInheritsAndModelStatements();
|
|
}
|
|
|
|
protected virtual void InjectDirective()
|
|
{
|
|
// @inject MyApp.MyService MyServicePropertyName
|
|
AssertDirective(InjectKeyword);
|
|
AcceptAndMoveNext();
|
|
|
|
Context.CurrentBlock.Type = BlockType.Directive;
|
|
|
|
// Accept whitespace
|
|
var remainingWs = AcceptSingleWhiteSpaceCharacter();
|
|
if (Span.Symbols.Count > 1)
|
|
{
|
|
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
|
|
}
|
|
Output(SpanKind.MetaCode);
|
|
|
|
if (remainingWs != null)
|
|
{
|
|
Accept(remainingWs);
|
|
}
|
|
|
|
// Consume any other whitespace tokens.
|
|
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
|
|
|
|
var hasTypeError = !At(CSharpSymbolType.Identifier);
|
|
if (hasTypeError)
|
|
{
|
|
Context.OnError(CurrentLocation,
|
|
Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(InjectKeyword));
|
|
}
|
|
|
|
// Accept 'MyApp.MyService'
|
|
NamespaceOrTypeName();
|
|
|
|
// typeName now contains the token 'MyApp.MyService'
|
|
var typeName = Span.GetContent().Value;
|
|
|
|
var propertyStartLocation = CurrentLocation;
|
|
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
|
|
|
|
if (!hasTypeError && (EndOfFile || At(CSharpSymbolType.NewLine)))
|
|
{
|
|
// Add an error for the property name only if we successfully read the type name
|
|
Context.OnError(propertyStartLocation,
|
|
Resources.FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(InjectKeyword));
|
|
}
|
|
|
|
// Read until end of line. Span now contains 'MyApp.MyService MyServiceName'.
|
|
AcceptUntil(CSharpSymbolType.NewLine);
|
|
if (!Context.DesignTimeMode)
|
|
{
|
|
// We want the newline to be treated as code, but it causes issues at design-time.
|
|
Optional(CSharpSymbolType.NewLine);
|
|
}
|
|
|
|
// Parse out 'MyServicePropertyName' from the Span.
|
|
var propertyName = Span.GetContent()
|
|
.Value
|
|
.Substring(typeName.Length);
|
|
|
|
Span.CodeGenerator = new InjectParameterGenerator(typeName.Trim(),
|
|
propertyName.Trim());
|
|
|
|
// Output the span and finish the block
|
|
CompleteBlock();
|
|
Output(SpanKind.Code);
|
|
}
|
|
|
|
private SpanCodeGenerator CreateModelCodeGenerator(string model)
|
|
{
|
|
return new ModelCodeGenerator(_baseType, model);
|
|
}
|
|
}
|
|
}
|